1 /* simple appletalk bridge for rodney
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/ioctl.h>
23 #include <netinet/in.h>
24 #include <netinet/ip.h>
25 #include <netinet/udp.h>
26 #include <arpa/nameser.h>
27 #include <arpa/inet.h>
28 #include <linux/if_ether.h>
32 #define MAX_PACKET_LENGTH 1600
33 #define HISTORY_LENGTH 20
35 /* we should use /etc/ethers but I'm too lazy */
37 #define HUB "00:00:0C:13:6F:18"
39 #define HUB "00:00:C0:81:93:8E"
41 #define ETH0 "00:00:C0:1B:A2:B8"
42 #define ETH1 "00:00:C0:6A:71:99"
44 static int eth_fd0 = -1;
45 static int eth_fd1 = -1;
47 static char *if_eth0 = "eth0"; /* name of ethernet interface */
48 static char *if_eth1 = "eth1"; /* name of ethernet interface */
50 static char data[MAX_PACKET_LENGTH];
52 static unsigned char hub_addr[ETH_ALEN];
53 static unsigned char eth0_addr[ETH_ALEN];
54 static unsigned char eth1_addr[ETH_ALEN];
56 static unsigned history[HISTORY_LENGTH];
57 static int history_pointer;
59 static unsigned eth0_counter, eth1_counter, dup_counter, ip_counter;
61 /* parse an ethernet address from string format to a byte array */
62 static void parse_ether(unsigned char *addr, char *addr_str)
65 if (sscanf(addr_str, "%x:%x:%x:%x:%x:%x",
67 &x[3], &x[4], &x[5]) != 6) {
68 fprintf(stderr,"couldn't parse %s\n", addr_str);
70 addr[0] = x[0]; addr[1] = x[1]; addr[2] = x[2];
71 addr[3] = x[3]; addr[4] = x[4]; addr[5] = x[5];
74 /* pretty-print an ethernet address */
75 static char *ether_str(unsigned char *addr)
83 sprintf(ret,"%02x:%02x:%02x:%02x:%02x:%02x",
84 addr[0], addr[1], addr[2],
85 addr[3], addr[4], addr[5]);
93 /* fetch the protocol field in a ethernet or 802 packet */
94 static unsigned get_protocol(char *data)
98 /* its either at offset 12 or 20 */
99 proto = *(unsigned short *)(data + 12);
100 proto = ntohs(proto);
103 /* it must be an 802 packet */
104 proto = *(unsigned short *)(data + 20);
105 proto = ntohs(proto);
111 /* a really simple checksum routine, probably quite hopeless */
112 static unsigned csum(char *data,int len)
117 sum ^= data[i] << ((i*15) % 28);
122 /* close the ethernet fd and set it back to non-promiscuous */
123 static void eth_close(int fd, char *interface)
127 strcpy(ifr.ifr_name, interface);
128 if(ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
129 perror("SIOCGIFFLAGS");
133 ifr.ifr_flags &= ~IFF_PROMISC;
134 if(ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
135 perror("SIOCSIFFLAGS");
144 /* open an ethernet socket for the requested protocol and
145 return a file descriptor that can be used for reading/writing packets
148 pstr specifies what packet types to accept
150 static int eth_open(char *interface, char *pstr)
156 if (!strcmp(pstr,"802.2")) protocol=ETH_P_802_2;
157 if (!strcmp(pstr,"802.3")) protocol=ETH_P_802_3;
158 if (!strcmp(pstr,"etherII")) protocol=ETH_P_IPX;
159 if (!strcmp(pstr,"echo")) protocol=ETH_P_ECHO;
160 if (!strcmp(pstr,"x25")) protocol=ETH_P_X25;
161 if (!strcmp(pstr,"arp")) protocol=ETH_P_ARP;
162 if (!strcmp(pstr,"atalk")) protocol=ETH_P_ATALK;
163 if (!strcmp(pstr,"aarp")) protocol=ETH_P_AARP;
164 if (!strcmp(pstr,"all")) protocol=ETH_P_ALL;
166 if (protocol == -1) {
167 printf("Unknown protocol [%s]\n",pstr);
171 if ((fd = socket(AF_INET, SOCK_PACKET, htons(protocol)))<0) {
172 perror("Error opening local ethernet socket\n");
176 strcpy(ifr.ifr_name, interface);
177 if(ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
178 perror("SIOCGIFFLAGS");
182 ifr.ifr_flags |= IFF_PROMISC;
183 if(ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
184 perror("SIOCSIFFLAGS");
192 static int eth_write(int fd, char *data, int len,char *iface)
196 dst.sa_family = AF_INET;
197 strcpy(dst.sa_data,iface);
199 return sendto(fd,data,len,0,&dst,sizeof(dst));
202 static int eth_read(int fd, char *buf)
204 struct sockaddr_in from;
205 size_t fromlen = sizeof(from);
207 return recvfrom(fd, buf, MAX_PACKET_LENGTH, 0,
208 (struct sockaddr *) &from, &fromlen);
211 static void Usage(void)
213 printf("Usage: \natalk_bridge\n\n");
214 printf("atalk_bridge [-f fr] [-0 eth0] [-1 eth1] port\n\n");
215 printf("fr = Ethernet frame type to bridge. Default is 802.2.\n");
216 printf(" Known values are:\n");
217 printf(" 802.2 802.3 etherII echo x25 arp atalk aarp all\n");
218 printf("if = Network interface to read from (default is eth0)\n");
222 void sig_int(int sig)
224 eth_close(eth_fd0, if_eth0);
225 eth_close(eth_fd1, if_eth1);
226 printf("Wrote %d packets to eth0\n", eth0_counter);
227 printf("Wrote %d packets to eth1\n", eth1_counter);
228 printf("%d duplicate packets dropped\n", dup_counter);
229 printf("%d IP packets processed\n", ip_counter);
234 /* this is the guts of the program. A packet has arrived and we need to decide
235 what to do with it */
236 static void process_packet(char *data, int len)
243 if (len <= 0) return;
245 sum = csum(data, len);
247 /* work out where it is from */
248 hdr = (struct ethhdr *)data;
249 protocol = get_protocol(data);
252 printf("packet %s -> %s len=%4d proto=%04x sum=%08x ",
253 ether_str(hdr->h_source),
254 ether_str(hdr->h_dest),
258 /* if the packet is from or to us then it makes no sense
260 if (memcmp(hdr->h_source, eth0_addr, ETH_ALEN) == 0 ||
261 memcmp(hdr->h_source, eth1_addr, ETH_ALEN) == 0 ||
262 memcmp(hdr->h_dest, eth0_addr, ETH_ALEN) == 0 ||
263 memcmp(hdr->h_dest, eth1_addr, ETH_ALEN) == 0) {
264 /* its from us, drop it */
266 printf("own packet\n");
271 /* don't process any ARP or RARP packets */
272 if (protocol == ETH_P_ARP || protocol == ETH_P_RARP) {
279 /* initially process IP packets to and from the hub, at
280 least until the bridge gets established. Once the arp tables
281 get flushed we will just be able to drop all these packets */
282 if (protocol == ETH_P_IP &&
283 memcmp(hdr->h_source, hub_addr, ETH_ALEN) == 0 &&
284 memcmp(hdr->h_dest, hub_addr, ETH_ALEN) == 0) {
291 /* is it a duplicate? */
292 for (i=0;i<HISTORY_LENGTH;i++)
293 if (sum == history[i]) {
295 printf("duplicate %d\n", i);
301 history[history_pointer] = sum;
302 history_pointer = (history_pointer+1) % HISTORY_LENGTH;
304 if (protocol == ETH_P_IP) {
305 printf("packet %s -> %s len=%4d proto=%04x sum=%08x\n",
306 ether_str(hdr->h_source),
307 ether_str(hdr->h_dest),
312 if (memcmp(hdr->h_source, hub_addr, ETH_ALEN) == 0) {
313 /* its from the hub (presumed to be on eth1). Send it to
318 printf("packet %s -> %s len=%4d proto=%04x sum=%08x\n",
319 ether_str(hdr->h_source),
320 ether_str(hdr->h_dest),
323 eth_write(eth_fd0, data, len, if_eth0);
325 /* its from a host on eth1, pass it on to eth1 */
330 eth_write(eth_fd1, data, len, if_eth1);
335 int main(int argc, char *argv[])
341 fprintf(stderr, "must be superuser\n");
345 fprintf(stderr,"atalk_bridge by Andrew Tridgell\n");
347 /* Process command-line args */
348 for(i=1; i<argc && argv[i][0]=='-'; ++i) switch(argv[i][1])
351 /* Selected frame types - from linux/if_ether.h */
354 case '0': if_eth0 = argv[++i]; break;
355 case '1': if_eth1 = argv[++i]; break;
361 parse_ether(hub_addr, HUB);
362 parse_ether(eth0_addr, ETH0);
363 parse_ether(eth1_addr, ETH1);
365 eth_fd0 = eth_open(if_eth0, pstr);
367 fprintf(stderr,"can't open %s\n", if_eth0);
371 eth_fd1 = eth_open(if_eth1, pstr);
373 fprintf(stderr,"can't open %s\n", if_eth1);
374 eth_close(eth_fd0, if_eth0);
378 signal(SIGINT, sig_int);
380 printf("bridge started\n");
388 FD_SET(eth_fd0, &rfd);
389 FD_SET(eth_fd1, &rfd);
394 no = select(32, &rfd, NULL, NULL, &tv);
396 if (no == -1 && errno != EAGAIN) {
397 printf("select error\n");
402 /* zero the history */
403 memset(history, 0, sizeof(history));
407 /* is anything happening on the ethernet? */
408 if (FD_ISSET(eth_fd0, &rfd)) {
409 len = eth_read(eth_fd0, data);
410 process_packet(data, len);
414 /* this is commented out as it seems that we get all
415 packets on both file sockets! */
416 if (FD_ISSET(eth_fd1, &rfd)) {
417 len = eth_read(eth_fd1, data);
418 process_packet(data, len);