📄 snap_kern_iface.c
字号:
/* * snap_kern_iface.c : interface between snap interpreter and the rest * of the kernel networking code */#include <asm/types.h>#include <sys/types.h>#include <assert.h>#include <errno.h>#include <features.h>#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1#include <netpacket/packet.h>#include <net/ethernet.h> /* the L2 protocols */#else#include <asm/types.h>#include <linux/if_packet.h>#include <linux/if_ether.h> /* The L2 protocols */#endif#include <sys/socket.h>#include <net/if.h>#include <net/if_arp.h>#include <netdb.h>#include <netinet/in_systm.h>#include <netinet/in.h>#include <netinet/ip.h>#include <stdlib.h>#include <sys/types.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/un.h>#include <unistd.h>#include "d_printf.h"#include "packet.h"#include "memalloc.h"#include "interface.h"#include "sockets.h"#include "pathnames.h"#include "intl.h"#include "net-support.h"#include "router.h"#include "io.h"#include "warn.h"struct iphdr {#if __BYTE_ORDER == __LITTLE_ENDIAN unsigned int ihl:4; unsigned int version:4;#elif __BYTE_ORDER == __BIG_ENDIAN unsigned int version:4; unsigned int ihl:4;#else# error "Please fix <bits/endian.h>"#endif u_int8_t tos; u_int16_t tot_len; u_int16_t id; u_int16_t frag_off; u_int8_t ttl; u_int8_t protocol; u_int16_t check; u_int32_t saddr; u_int32_t daddr; /*The options start here. */ };#define NIPQUAD(addr) \ ((unsigned char *)&(addr))[0], \ ((unsigned char *)&(addr))[1], \ ((unsigned char *)&(addr))[2], \ ((unsigned char *)&(addr))[3]#ifdef CONFIG_IP_SNAPstatic inline unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);#ifdef CONFIG_IP_SNAP_DEBUGint sysctl_snap_debug_level = 0;#endif /* CONFIG_IP_SNAP_DEBUG *//* hardware interface definitions */struct if_info { struct if_nameindex ifni; __u32 addr; char hwaddr[32];};/* hardware interface variables */struct sockaddr_in *thishosthint = NULL;struct hostent *thishe = NULL;unsigned int numifs = 0;struct if_info *ifs = NULL;unsigned int maxifnum = 0;unsigned int ifs_size = 0;/* the send sockets */static int rawip_send_ra_socket;void init_kern_iface(struct sockaddr_in *hint) { char hostname[128]; struct if_nameindex *allifs; struct if_nameindex *currif; struct interface ife; unsigned char ra_space[4]; /* get the primary hostname */ if ((hint != NULL) && (hint->sin_addr.s_addr != 0)) { thishosthint = hint; } if (gethostname(hostname,sizeof(hostname)) < 0) { perror("gethostname"); exit(EXIT_FAILURE); } if ((thishe = gethostbyname(hostname)) == NULL) { herror("gethostbyname"); fprintf(stderr,"debug >> error while trying to resolve %s\n",hostname); exit(EXIT_FAILURE); } if ((rawip_send_ra_socket = socket(AF_INET, SOCK_RAW, IPPROTO_SNAP)) < 0) { perror("snap_kern_iface: rawip_send_ra_socket: socket()"); exit(EXIT_FAILURE); } ra_space[IPOPT_OPTVAL] = IPOPT_RA; ra_space[IPOPT_OLEN] = 4; ra_space[2] = ra_space[3] = 0; if (setsockopt(rawip_send_ra_socket, IPPROTO_IP, IP_OPTIONS, ra_space, sizeof(ra_space)) < 0) { perror("rawip_send_ra_socket: router alert setsockopt()"); exit(EXIT_FAILURE); } /* retrieve the active interfaces from the kernel */ if ((skfd = sockets_open()) < 0) { perror("skfd: sockets_open()"); exit(EXIT_FAILURE); } /* collect IFACE info from glibc functions */ if ((allifs = if_nameindex()) == NULL) { perror("if_nameindex"); exit(EXIT_FAILURE); } for (currif = allifs; (currif->if_index != 0) && (currif->if_name != NULL); currif++) { if (currif->if_index > maxifnum) { maxifnum = currif->if_index; } numifs++; } d_printf(40,"found %d interfaces\n",numifs); assert(maxifnum > 0); /* get additional IFACE info from local functions */ memalloc(ifs,struct if_info *,sizeof(struct if_info) * (maxifnum + 1)); ifs_size = maxifnum + 1; for (currif = allifs;(currif->if_index != 0) && (currif->if_name != NULL); currif++) { (void)if_fetch(currif->if_name, &ife); ifs[currif->if_index].ifni.if_index = currif->if_index; ifs[currif->if_index].ifni.if_name = currif->if_name; ifs[currif->if_index].addr = (*(struct sockaddr_in *)(&ife.addr)).sin_addr.s_addr; memcpy(ifs[currif->if_index].hwaddr, ife.hwaddr, 32); d_printf(45,"if_index %d = %s inaddr = %d.%d.%d.%d\n", currif->if_index,currif->if_name, NIPQUAD((*(struct sockaddr_in *)(&ife.addr)).sin_addr.s_addr)); fflush(stderr); } /* read additional IFACE and ROUTE info from /proc NB: IFACE info from /proc/net/dev is used for ifacename<->ifaceindex translation I don't know why Jon implemented this. */ read_ifaces(PROC_NET_DEV_PATH); read_routes(PROC_NET_ROUTE_PATH);}/* returns one of the current host's IP addresses, preferably not 127.0.0.1 */#ifdef __KERNEL__int snap_here(u32 *addr, struct sk_buff *skb) {#elseint snap_here(__u32 *addr, packet_t *p) {#endif int i; __u32 tmpaddr; if (thishosthint != NULL) { d_printf(50,"%s:%d: HERE: found non-loopback addr\n", __FILE__,__LINE__); *addr = thishosthint->sin_addr.s_addr; return 0; } assert(thishe != NULL); for(i=0; thishe->h_addr_list[i] != NULL; i++) { tmpaddr = *(__u32 *)thishe->h_addr_list[i]; if (tmpaddr != htonl(INADDR_LOOPBACK)) { d_printf(50,"%s:%d: HERE: found non-loopback addr\n", __FILE__,__LINE__); *addr = tmpaddr; return 0; } } if (i > 0) { d_printf(50,"%s:%d: HERE: ran through %d ifs, all loopback!\n", __FILE__,__LINE__,i); *addr = *(__u32 *)thishe->h_addr_list[0]; return 0; } return -1;}#ifdef __KERNEL__int getdevindex(struct device *dev_in) { return -1; /* not found */}#endifint next_hop(__u32 *hop, __u32 daddr, /* where we are headed */ int tos ) { /* type of service */ struct rt_lookup rt; if (nexthop(daddr,&rt) < 0) { *hop = 0; return -1; } *hop = rt.hopaddr; return 0;}#ifdef __KERNEL__int ishere(__u32 addr, struct sk_buff *skb) {#elseint ishere(__u32 addr, packet_t *p) {#endif int i; struct if_info *curr; for(i=0; i<=maxifnum; i++) { curr = &ifs[i]; d_printf(100,"%s:%d: curr=%d, here=(%d.%d.%d.%d)\n", __FILE__,__LINE__,i,NIPQUAD(curr->addr)); if ((curr->ifni.if_index != 0) && (curr->ifni.if_name != NULL) && (curr->addr == addr)) { d_printf(100,"%s:%d: ishere(%d.%d.%d.%d) -> YES\n", __FILE__,__LINE__,NIPQUAD(addr)); return 1; } } d_printf(100,"%s:%d: ishere(%d.%d.%d.%d) -> NO\n", __FILE__,__LINE__,NIPQUAD(addr)); return 0;}/* protocol specific demux send handlers*/#include "../src/snap_demux_handler.h"#ifdef __KERNEL__int snap_demux_send_unix(__u16 destport, struct sk_buff *skb, void *s, unsigned int slen) {#elseint snap_demux_send_unix(__u16 destport, packet_t *p, void *s, unsigned int slen) {#endif int usock; struct sockaddr_un laddr; d_printf_timed(7,"snap_demux_send_unix : creating socket\n"); if ((usock = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) { perror("snap_demux_send_unix: socket()"); return -1; } d_printf_timed(7,"snap_demux_send_unix : creating sockaddr_un struct\n"); laddr.sun_family = AF_UNIX; sprintf(laddr.sun_path, "/tmp/snap%d",destport); d_printf_timed(7,"snap_demux_send_unix : sending \n"); if (sendto(usock, s, slen, 0, (struct sockaddr *)&laddr, sizeof(laddr)) < slen) { perror("snap_demux_send_unix: sendto()"); return -1; } d_printf_timed(7,"snap_demux_send_unix : finished \n"); close(usock); return 0;}#ifdef __KERNEL__int snap_demux_send_rawip(__u16 destport, struct sk_buff *skb, void *s, unsigned int slen) {#elseint snap_demux_send_rawip(__u16 destport, packet_t *p, void *s, unsigned int slen) {#endif struct sockaddr_in bindaddr; int socket_rawip; if ((socket_rawip = socket(AF_INET, SOCK_RAW, IPPROTO_SNAP)) < 0) { perror("snap_demux_send_rawip: socket()"); return 1; } memset(&bindaddr, 0, sizeof(bindaddr)); bindaddr.sin_family = AF_INET; bindaddr.sin_addr.s_addr = htonl( (127 << 24) + 1 ); /* == 127.0.0.1 */ if (sendto(socket_rawip, s, slen, 0, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < slen) { perror("snap_demux_send_udp: sendto()"); close (socket_rawip); return -1; } close (socket_rawip); return 0;}#ifdef __KERNEL__int snap_demux_send_udp(__u16 destport, struct sk_buff *skb, void *s, unsigned int slen) {#elseint snap_demux_send_udp(__u16 destport, packet_t *p, void *s, unsigned int slen) {#endif struct sockaddr_in bindaddr; int socket_udp; d_printf_timed(7,"snap_demux_send_udp : creating socket\n"); if ((socket_udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("snap_demux_send_udp: socket()"); return 1; } d_printf_timed(7,"snap_demux_send_udp : creating sockaddr_in struct\n"); memset(&bindaddr, 0, sizeof(bindaddr)); bindaddr.sin_family = AF_INET; bindaddr.sin_addr.s_addr = htonl( (127 << 24) + 1 ); /* == 127.0.0.1 */ bindaddr.sin_port = htons(destport); d_printf_timed(7,"snap_demux_send_udp : sending \n"); if (sendto(socket_udp, s, slen, 0, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < slen) { perror("snap_demux_send_udp: sendto()"); close(socket_udp); return -1; } close(socket_udp); d_printf_timed(7,"snap_demux_send_udp : finished \n"); return 0;}/* handle demux instruction. Outgoing interfaces can be selected by setting an environment variable. For backward compatibility purposes handling defaults to a unix pipe*/#ifdef __KERNEL__int snap_demux_send(__u16 destport, struct sk_buff *skb, void *s, unsigned int slen) {#elseint snap_demux_send(__u16 destport, packet_t *p, void *s, unsigned int slen) {#endif int protocols; int returnvals = 0; char* env_val; d_printf_timed(7,"snap_demux_send : preparing for send ..\n"); /* retrieve the protocols */ env_val = getenv("SNAP_DEMUX_HANDLER"); if (env_val != NULL) protocols = atoi(env_val); else protocols = SNAP_UDP; if (protocols & SNAP_UNIX) returnvals += snap_demux_send_unix(destport, p, s, slen); if (protocols & SNAP_RAWIP) returnvals += snap_demux_send_rawip(destport, p, s, slen); if (protocols & SNAP_UDP) returnvals += snap_demux_send_udp(destport, p, s, slen); d_printf_timed(7,"snap_demux_send : .. sent message\n"); return returnvals;}int snap_send_packet(packet_t *p, int stack_amt, __u32 dest, unsigned char rb, int ep, short direct) { struct snaphdr *sh; buffer_t newbuf; __u32 hopaddr; struct rt_lookup rt; struct iphdr *newiph; struct sockaddr_in hopipaddr; d_printf(60,"snap_send_packet : marshalling packet and initializing structure\n"); if (marshal_packet(p, stack_amt, &newbuf)) { warn("%s:%d: marshal_packet failed\n",__FILE__,__LINE__); return -1; } /* modify the snapheader */ newiph = (struct iphdr *)newbuf.s; sh = (struct snaphdr *)(newbuf.s + newiph->ihl * 4); sh->entry_point = htons(ep); sh->daddr = dest; /* create the ip header */ newiph->daddr = dest; newiph->ttl = rb; newiph->check = 0; newiph->check = ip_fast_csum((unsigned char *)newiph, newiph->ihl); /* initialize the sockaddr structure */ memset(&hopipaddr, 0, sizeof(hopipaddr)); hopipaddr.sin_family = AF_INET; /* calculate the next hop only if we do not want a direct connection */ if (!direct){ if (nexthop(dest,&rt) < 0) /* find next IP hop */ return -1; hopaddr = rt.hopaddr; d_printf(100,"%s:%d: indirect send to next hop: %d.%d.%d.%d, ifindex %d\n",__FILE__,__LINE__,NIPQUAD(hopaddr),rt.ifidx); hopipaddr.sin_addr.s_addr = hopaddr; } else { d_printf(100,"%s:%d: direct send to next host: %d.%d.%d.%d, ifindex unknown\n",__FILE__,__LINE__,NIPQUAD(dest)); hopipaddr.sin_addr.s_addr = dest; }#ifdef LINUX if (setsockopt(rawip_send_ra_socket, IPPROTO_IP, IP_TTL, (char *)&rb, sizeof(rb)) < 0) { perror("rawip_send_ra_socket: ttl setsockopt()"); return -1; }#else//freeBSD int ttl_int = (int) rb; if (setsockopt(rawip_send_ra_socket, IPPROTO_IP, IP_TTL, (void *)&ttl_int, sizeof(int)) < 0) { perror("rawip_send_ra_socket: ttl setsockopt()"); return -1; }#endif d_printf(60,"snap_send_packet : sending packet\n"); if (sendto(rawip_send_ra_socket, sh, newbuf.lenb - (newiph->ihl * 4), 0, (struct sockaddr *)&hopipaddr, sizeof(hopipaddr)) != newbuf.lenb - (newiph->ihl * 4)) { perror("rawip_send_ra_socket: sendto()"); return -1; } d_printf(60,"snap_send_packet : finished\n"); return 0;}packet_t *pkt_dup(packet_t *p) { return NULL;}int next_hop_and_dev(__u32 *hop, int *dev, __u32 daddr) { struct rt_lookup rt; if (nexthop(daddr, &rt) < 0) { *hop = 0; *dev = 0; return -1; } *hop = rt.hopaddr; *dev = rt.ifidx; return 0;}static inline unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) { unsigned int sum; __asm__ __volatile__("\n\ movl (%1), %0 \n\ subl $4, %2 \n\ jbe 2f \n\ addl 4(%1), %0 \n\ adcl 8(%1), %0 \n\ adcl 12(%1), %0 \n\1: adcl 16(%1), %0 \n\ lea 4(%1), %1 \n\ decl %2 \n\ jne 1b \n\ adcl $0, %0 \n\ movl %0, %2 \n\ shrl $16, %0 \n\ addw %w2, %w0 \n\ adcl $0, %0 \n\ notl %0 \n\2: \n\ " /* Since the input registers which are loaded with iph and ipl are modified, we must also specify them as outputs, or gcc will assume they contain their original values. */ : "=r" (sum), "=r" (iph), "=r" (ihl) : "1" (iph), "2" (ihl)); return(sum);}#endif /* CONFIG_IP_SNAP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -