📄 ethersim.c
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees * of Leland Stanford Junior University. * * This file is part of the SimOS distribution. * See LICENSE file for terms of the license. * *//* * ethersim.c -- * * Simuation of a local ethernet with a gateway interface. * This program simulates a local ethernet with a gateway machine * attached to it. The simulated ethernet accepts ethernet packets * that arrive on the special UDP port. It is assumed that these * packets are send by the network module of simos services running * on top of Unix. This program decodes the ethernet header and * uses it to determine which UDP port to output the packet on. * This is done by keeping track of the ethernet address of the machine * sending packets to the ethernet port. * * When this program receives an ethernet packet of type IP to an IP * destination address outside the subnet of the local ethernet, it * outputs the packet to the local (phsyical) ethernet attached to * the machine. By doing this the program acts like a gateway machine. * * The gateway could be running on two kinds of machines: mips and * sparc. On SGI's mips machine, the program uses SNOOP protocol, * while * The program also opens the network interface of the machines and * grabs any packets with an IP destination of the simulated subnet. * This is done using Sun's NIT protocol and packet filter. Packets * addressed to a known simulated host will be forward on to that * host's UDP port. * * NOTES: * 1) Because this program uses NIT to get packets from the outside * packets arriving at network interfaces other than the one * specified are not seen. In particular, packets sent thru * the loopback (lo0) interface are not seen by this program. * This means that processes on the local machine can't talk IP * to the simulated machines. * 2) This program is a big security hole because it accepts packets * from an non-privledged UDP port and forwards them on to the * local ethernet. I think that outputPacket() does enough * checking to stop this from being a problem. * */#include "ethersim.h"/* * Program options setable from the command line. */u_long subnetaddr = 0x24840000; /* Subnet address (i.e. 36.132.0.0). */int simportnumber = ETHER_SIM_PORT; /* UDP port of simulated ethernet. */int noipforwarding = 0; /* Boolean - Don't forward ip packet. */char interfacename[32] = "et0"; /* Name of interface to forward IP */u_long routeraddr = (u_long)-1;#ifdef SIM_PROXY#define MAX_ADDRS 16u_long nproxys = 0;u_long proxyaddr[MAX_ADDRS];#endifextern int arpverbose;int verbose = 1;/* * Buffer to hold the current packet being transmitted on the ethernet. * This must be big enought to hold an ethernet MTU and its header. We * add 128 bytes for good measure. */char curPacket[ETHERMTU + sizeof(struct ether_header) + 128];int simfd; /* Open file descriptor of simulated ethernet port. */int netfd; /* Open file descriptor of network interface tap. *//* * The ethernet address and IP network address of the interface being used. */u_char myetheraddr[6];u_long mynetaddr;/* * The internet address and netmask of the interface being used. */u_long myinetAddr;u_long mynetmask;/* * Hash tables that map * etheraddrTable - Ethernet addresses to HostInfoRecord. * ipaddrTable - IP addresses to HostInfoRecord. */Hash_Table etheraddrTable;Hash_Table ipaddrTable;/* *---------------------------------------------------------------------- * * main -- * * Main routine and loop for ethersim. * * Results: * Only returns if an error occurs. * * Side effects: * *---------------------------------------------------------------------- */intmain(int argc, char *argv[]){ int c, errflg; struct sockaddr_in addr; int nfds; struct pollfd fds[3]; int (*serviceRoutine[3])(void); simfd = netfd = -1; errflg = 0;#ifdef SIM_PROXY#define OPTS "fg:p:n:r:x:i:v"#else#define OPTS "fg:p:n:r:i:v"#endif while ((c = getopt(argc, argv, OPTS)) != -1) { switch (c) { case 'f': noipforwarding = 1; break; case 'i': strncpy(interfacename, optarg, sizeof(optarg)-1); break; case 'g': subnetaddr = inet_network(optarg); if (subnetaddr == (u_long) -1) { fprintf(stderr, "%s: Malformed gateway address %s\n", argv[0], optarg); errflg++; } break;#ifdef SIM_PROXY case 'x': proxyaddr[nproxys] = inet_network(optarg); if (proxyaddr[nproxys] == (u_long) -1) { fprintf(stderr, "%s: Malformed proxy address %s\n", argv[0], optarg); errflg++; } nproxys++; break;#endif case 'r': routeraddr = inet_network(optarg); if (routeraddr == (u_long) -1) { fprintf(stderr, "%s: Malformed router address %s\n", argv[0], optarg); errflg++; } break; case 'p': simportnumber = atoi(optarg); if (simportnumber < 0) { fprintf(stderr, "%s: Illegal port number %s\n", argv[0], optarg); errflg++; } break; case 'v': verbose = 1; arpverbose = 1; break; case '?': errflg++; } } if (errflg) { (void)fprintf(stderr, "usage: %s [-g netaddr] [-p portnumber] [-n netmask]\n", argv[0]); exit (2); } /* * Create the socket that transmits on the simulated ethernet will be * sent. It is a UDP port number ETHER_SIM_PORT. The mostly likely * cause of failure is another ethersim running causing the bind * to fail with address in use. */ simfd = socket(AF_INET, SOCK_DGRAM, 0); if (simfd < 0) { perror("main: socket"); exit(1); } simportnumber = ETHER_SIM_PORT; bzero((char *)&addr, sizeof(addr)); addr.sin_port = htons(simportnumber); addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_family = AF_INET; if (bind(simfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("main: bind"); exit(2); } if (!noipforwarding && (geteuid() != 0)) { fprintf(stderr, "%s: not running as root - IP forwarding disabled\n", argv[0]); noipforwarding = 1; } if (!noipforwarding) { if (lookupInterface(interfacename, &myinetAddr, &mynetmask) < 0) { fprintf(stderr, "Couldn't find interface %s\n", interfacename); exit(3); } { struct in_addr tmp; tmp.s_addr = myinetAddr; mynetaddr = inet_netof(tmp); } if(verbose) { printf("Address:0x%x, Netmask:0x%x\n", myinetAddr,mynetmask); }#ifdef SIM_PROXY netfd = initSNPdevice(interfacename, proxyaddr, nproxys, 0xffffffff);#else netfd = initSNPdevice(interfacename, subnetaddr, mynetmask);#endif if (netfd < 0) { fprintf(stderr, "Couldn't initialize network tap\n"); exit(3); } } /* * Initialize mapping hash tables. */ Hash_InitTable(ðeraddrTable, 0, 2); Hash_InitTable(&ipaddrTable, 0, HASH_ONE_WORD_KEYS); /* * Loop waiting for packets to arrive. */ nfds = 0; fds[nfds].fd = simfd; fds[nfds].events = POLLIN; serviceRoutine[nfds] = serviceSimPort; nfds++; if (netfd >= 0) { fds[nfds].fd = netfd; fds[nfds].events = POLLIN; serviceRoutine[nfds] = serviceNetPort; nfds++; } while (1) { int n; int i; fds[0].revents = fds[1].revents = fds[2].revents = 0; n = poll(fds, nfds, -1); if (n < 0) { if (errno == EINTR) continue; perror("poll"); exit(1); } for (i = 0; i < nfds; i++) { if (fds[i].revents & POLLIN) { (void) serviceRoutine[i](); } } }}voiddispEtherPacket(int n, struct ether_header* hdrPtr, int tab){ struct ip *ipPtr; struct udphdr *udpPtr; struct tcphdr *tcpPtr; char *dataPtr; struct in_addr ipdst, ipsrc; char blankhead[40]; if (tab == 0) sprintf(blankhead,"%s"," "); else if (tab == 1) sprintf(blankhead,"%s","\t\t"); else if (tab == 2) sprintf(blankhead,"%s","\t\t\t\t"); printf("%s<S>%x:%x:%x:%x:%x:%x\n",blankhead,A(0),A(1),A(2),A(3),A(4),A(5)); printf("%s<D>%x:%x:%x:%x:%x:%x\n",blankhead,B(0),B(1),B(2),B(3),B(4),B(5)); if (htons(hdrPtr->ether_type) == ETHERTYPE_IP) printf("%sether_type = IP\n",blankhead); else if (htons(hdrPtr->ether_type) == ETHERTYPE_ARP)#ifdef SIM_PROXY { struct ether_arp *arpHdr; u_char *c; printf("%sether_type = ARP\n",blankhead); arpHdr = (struct ether_arp *) ((char*)hdrPtr + sizeof(struct ether_header)); c = arpHdr->arp_sha; printf("%s<SE>%x:%x:%x:%x:%x:%x\n", blankhead, c[0],c[1],c[2],c[3],c[4],c[5]); c = arpHdr->arp_spa; printf("%s<SIP>%d.%d.%d.%d\n", blankhead, c[0],c[1],c[2],c[3]); c = arpHdr->arp_tha; printf("%s<TE>%x:%x:%x:%x:%x:%x\n", blankhead, c[0],c[1],c[2],c[3],c[4],c[5]); c = arpHdr->arp_tpa; printf("%s<TIP>%d.%d.%d.%d\n", blankhead, c[0],c[1],c[2],c[3]); return; }#else printf("%sether_type = ARP\n",blankhead);#endif else printf("%sether_type = %u\n",blankhead,(hdrPtr->ether_type)); ipPtr = (struct ip *) ((char*)hdrPtr + sizeof(struct ether_header)); bcopy((u_char*)& ipPtr->ip_src, (u_char*)& ipsrc.s_addr ,sizeof(u_long)); bcopy((u_char*)& ipPtr->ip_dst, (u_char*)& ipdst.s_addr ,sizeof(u_long)); printf("%s<S>0x%x(%s)\n",blankhead,(ipsrc.s_addr), inet_ntoa(ipsrc)); printf("%s<D>0x%x(%s)\n",blankhead,(ipdst.s_addr), inet_ntoa(ipdst)); printf("%sip_len:%d\n",blankhead,(ipPtr->ip_len)); if ( htons(ipPtr->ip_p )== IPPROTO_TCP) { printf("%sTCP:\n",blankhead); tcpPtr = (struct tcphdr *) ((char*) ipPtr + sizeof(struct ip)); dataPtr = (char*) ((char*)tcpPtr + sizeof(struct tcphdr)); } else if (htons(ipPtr->ip_p )== IPPROTO_UDP) { printf("%sUDP:\n",blankhead); udpPtr = (struct udphdr*) ((char*) ipPtr + sizeof(struct ip)); dataPtr = (char*) ((char*)udpPtr + sizeof(struct udphdr)); } else if (htons(ipPtr->ip_p) == IPPROTO_ICMP){ printf("%sICMP:\n",blankhead); } else if (htons(ipPtr->ip_p) == IPPROTO_IGMP){ printf("%sIGMP:\n",blankhead); } else if (htons(ipPtr->ip_p) == IPPROTO_GGP){ printf("%sGGP:\n",blankhead); } else if (htons(ipPtr->ip_p) == IPPROTO_RAW){ printf("%sRAW:\n",blankhead); } else printf("%sprotocol:%d\n",blankhead,htons(ipPtr->ip_p)); }/* *---------------------------------------------------------------------- * * validPacket -- * * Check to see if we should accept this packet. * * Results: * 1 if packet ok. * 0 if we should request it. * * Side effects: * *---------------------------------------------------------------------- */intvalidPacket( char *packet, /* The contents of the packet. */ int size, /* The size of the packet. */ struct sockaddr *fromAddr, /* Where the packet was from. */ int fromlen /* The length of fromAddr. */){ struct ether_header *hdrPtr; struct sockaddr_in *inaddrPtr; u_long srcAddr; hdrPtr = (struct ether_header *) packet; if ((size < ETHERMIN + sizeof(struct ether_header)) || (size > ETHERMTU + sizeof(struct ether_header))) { fprintf(stderr, "Bad packet size %d\n", size); return 0; } /* * XXX - Do security checking here. Currently we reject all packets * from hosts outside our network. We only if we are forwarding * packets. */ if (!noipforwarding) { if ((fromAddr->sa_family != AF_INET) || (fromlen < offsetof(struct sockaddr_in, sin_zero))) { fprintf(stderr, "Packet from bad fromaddr\n"); return 0; } inaddrPtr = (struct sockaddr_in *) fromAddr; srcAddr = inet_netof(inaddrPtr->sin_addr); if ((srcAddr != mynetaddr) && (srcAddr != IN_LOOPBACKNET)) { fprintf(stderr, "Security violation: Packet from host %s\n", inet_ntoa(inaddrPtr->sin_addr)); return 0; } } return 1;}/* *---------------------------------------------------------------------- * * lookupInterface -- * * Find the specified interface and read its address and netmask. * * * Results: * 0 if we found things, -1 otherwise. * * Side effects: * *---------------------------------------------------------------------- */intlookupInterface(char *interfacename, u_long *inetAddrPtr, u_long *netmaskPtr){ char cmdBuf[256]; char inetString[32], netmaskString[32]; int ch; FILE *pfile; /* * We cheat and use ifconfig to lookup the info. This should probably * be changed to do all kinds of nasty I/O controls to lookup the info. */ sprintf(cmdBuf, "/usr/etc/ifconfig %s", interfacename); pfile = popen(cmdBuf, "r"); if (pfile == (FILE *) NULL) { fprintf(stderr, "Can't execute %s\n", cmdBuf); return -1; } /* * Skip the first line which should look something like: * le0: flags=63<UP,BROADCAST,NOTRAILERS,RUNNING> */ for (ch = fgetc(pfile); (ch != '\n') && (ch != EOF); ch = fgetc(pfile)) ; if (fscanf(pfile, "\tinet %s netmask %s ", inetString, netmaskString) != 2){ (void) pclose(pfile); } *inetAddrPtr = inet_addr(inetString); *netmaskPtr = strtoul(netmaskString, (char **)NULL, 16); if (routeraddr == (u_long) -1) { routeraddr = ((*inetAddrPtr) & (*netmaskPtr)) | 1; /* Default to host 1 on the network */ } (void) pclose(pfile); return 0;}unsigned long FindGateway(unsigned long dstaddr){ if ((dstaddr & mynetmask) == (myinetAddr & mynetmask)) return dstaddr; if ((dstaddr & mynetmask) == subnetaddr) return -1; return routeraddr;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -