Date: Tue, 19 Jul 2005 11:56:07 +0200 From: Lasaro Camargos <camargol@lu.unisi.ch> To: freebsd-ipfw@freebsd.org Subject: Interception/Injection. Message-ID: <B9D82A16-2113-45C7-9426-8F1A5EAA2032@lu.unisi.ch>
next in thread | raw e-mail | index | archive | help
Hi all, I've been playing with interception and re-injection of diverted packets but I am having some problems. The biggest is that I am not really using freebsd, but OSX. But I guess the problems are general enough to be answered here. If not, please ignore this message. The situation is the following: as I didn't find any multicast router for OSX I was obliged to implement one. So I am diverting multicast packets from one interface to the other. Specifically, I divert incoming to a program that reinsert it back in the stack to be received by the router, and inserting a copy of it as outgoing on the other interface (I don't know why, but tee seems not to work). I am aware of possible security implications of this "solution", but it is going to be used in a very restricted environment. By using to instances of my code I am able to forward multicast packets between two networks, and that is good. BUT, when the router/forwarder machine (RFM) also send/receive multicast packets, I find some problems: a multicast packet sent by RFM is diverted but, after reinserted, both original incoming and forced outgoing packets they simply vanish. if the packet is not diverted, RFM receive it, but (of course) not the machines in the network to where the packets should be forwarded. My code and more details of my environment are attached in the bottom. Any comment/pointer is really welcome. Thank you all Lasaro. ------------------- /* ********** This is a program that I use to forward multicast packets on OSX (should work on other BSDs). It will forward any packet diverted (teed) to the raw sockets it listens, though. To use it, create a rule in ipfw to divert packets like this: >> ipfw add divert 5000 from 192.168.0.0/24 to 239.0.0.0/8 recv en0 this rule will divert any multicast packet comming from the network 192.168.0.0/24 entering through the iface en0 (see 1) for multicast addresses in the range 239.0.0.0 - 239.255.255.255 to port 5000. If the router should also receive the packet, use tee instead of divert (see 2). Remember that a teed packet will be immediatelly accepted by ipfw. If you don't want this, you'll have to work on your rules (see 3). diverter 5000 192.168.1.1 #running like this, diverter will forward diverted packets to the network connected in the interface with address 192.168.1.1 Someday I will add the code to add the rule into ipfw from inside this program. Open issues (and possible solutions) : i) loops in the routing. by now, specify both network and interface from where the packet is comming. The last example get rid of loops. (1) ii) loopback delivery have to setsockopt( , MULTICAST_LOOP , 0 ,); or something like that. iii) sending multicast on two interfaces from the router. ipfw add tee 5000 from IP_MULTICAST_INTERFACE to 239.0.0.0/8 out diverter 5000 THE_OTHER_INTERFACE iv) tee not working see next v) security problem with tee use divert in the rule and define __TEE__ to duplicate the packet inside this code. (3) running example: on the router en0: 192.168.0.9/24 en1: 192.168.1.9/24 sudo ipfw add 9 skipto 11 udp from me to 230.2.3.10 recv en0 sudo ipfw add 10 divert 10000 udp from 192.168.0.0/24 to 230.2.3.10 recv en0 sudo ipfw add 11 skipto 13 udp from me to 230.2.3.10 recv en1 sudo ipfw add 12 divert 10001 udp from 192.168.1.0/24 to 230.2.3.10 recv en1 ipfw list 00009 skipto 11 udp from me to 230.2.3.10 recv en0 00010 divert 10000 udp from 192.168.0.0/24 to 230.2.3.10 recv en0 00011 skipto 13 udp from me to 230.2.3.10 recv en1 00012 divert 10001 udp from 192.168.1.0/24 to 230.2.3.10 recv en1 65535 allow ip from any to any everything running except that packets from itself are not forwarded to net 192.168.1.0/24. This is, of course, because of rule 9. But if I remove this rule, diverted packets are received by the router nor in the net 192.168.1.0/24. The packets are being reinserted but not delivered by the application. I can't identify where the packet is being lost. Any idea of which log file should I look at? */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <limits.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/param.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <netinet/udp.h> #include <net/if.h> #include <net/if_dl.h> #include <arpa/inet.h> #include <ifaddrs.h> #define __DEBUG__ #define __TEE__ #define __IP_MULTICAST__ #define BUFSIZE 65535 int main(int argc, char ** argv) { int sock_fd, data_len, ret, i; struct sockaddr_in bindPort, sin; int sinlen = sizeof(struct sockaddr_in); unsigned char packet[BUFSIZE]; struct ip *hdr; struct in_addr out_iface; if (argc != 3) { fprintf(stderr, "This is a packet forwarder.\nAdd an \"in\" divert (or tee) rule to ipfw to port <port number>.\nPackets diverted will be outbounded on interface <out iface>. CAUTION!! Remember that by now \"tee\"d packets will be imediatelly accepted and that reinjected packets will be processed by the next ipfw rule, not the first.\n Usage: %s <port number> <out iface IP>\n error: %i\n", argv [0],errno); exit (1); } if(inet_aton(argv[2], &out_iface) != 1) { fprintf(stderr, "%s: wrong IP address param.\n", argv[0]); exit (1); } //Create socket fprintf(stderr, "%s:creating a raw socket\n",argv[0]); sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_DIVERT); if(sock_fd == -1) { fprintf(stderr, "%s: Unable to open divert socket (%i) \n", argv [0],errno); switch(errno) { case EACCES: fprintf(stderr, "EACCESS\n"); break; case EMFILE: fprintf(stderr, "EMFILE\n"); break; case ENFILE: fprintf(stderr, "ENFILE\n"); break; case ENOBUFS: fprintf(stderr, "ENOBUFFS\n"); break; case EPROTONOSUPPORT: fprintf(stderr, "PROTONOSUPPORT\n"); break; default:break; } exit(1); } //Bind on port fprintf(stderr, "%s: Binding a socket\n",argv[0]); bindPort.sin_family = AF_INET; bindPort.sin_port = atol(argv[1]); bindPort.sin_addr.s_addr=0; if( (ret = bind(sock_fd, (struct sockaddr *)&bindPort, sizeof (struct sockaddr_in))) != 0) { close(sock_fd); fprintf(stderr, "%s:Error executing bind():%s\n", argv [0],strerror(ret)); exit(2); } #ifdef __IP_MULTICAST__ fprintf(stderr, "%s: Setting IP MULTICAST interface to %s\n",argv [0],argv[2]); ret = setsockopt(sock_fd, IPPROTO_IP, IP_MULTICAST_IF, &out_iface, sizeof(out_iface)); #ifdef __DEBUG__ if(ret < 0) fprintf(stderr,"%s: set_interface returns %i with errno %i: %s \n", argv[0], ret, errno, strerror(errno)); #endif //__DEBUG__ #endif //__IP_MULTICAST__ /* Wait for packets. */ fprintf(stderr,"\%s:Waiting for data.", argv[0]); while(1) { /* Capture */ data_len = recvfrom(sock_fd, packet, BUFSIZE, 0, (struct sockaddr *)&sin, (socklen_t *)&sinlen); hdr = (struct ip*) packet; #ifdef __DEBUG__ fprintf(stderr,"%s:The packet looks like this:\n\t", argv[0]); for( i = 0; i < data_len; i++) { fprintf(stderr,"%02x ", (int)*(packet+i)); if(!((i+1) %16)) fprintf(stderr,"\n\t"); }; fprintf(stderr,"\n\n\t"); for( i = 28; i < data_len; i++) { fprintf(stderr,"%c", (char)*(packet+i)); if(!((i-28+1) %16)) fprintf(stderr,"\n\t"); }; fprintf(stderr,"\n"); #endif #ifdef __DEBUG__ fprintf(stderr,"%s: Source address %s\n", argv[0], inet_ntoa (hdr->ip_src)); fprintf(stderr,"%s: Destination address %s\n", argv[0], inet_ntoa (hdr->ip_dst)); fprintf(stderr,"%s: Receiving IF address %s\n",argv[0], inet_ntoa (sin.sin_addr)); fprintf(stderr,"%s: Protocol Number %i\n", argv[0], hdr->ip_p); #endif /* Reinjection */ #ifdef __DEBUG__ if(IN_MULTICAST((ntohl(hdr->ip_dst.s_addr)))) { fprintf(stderr,"\%s: Multicast address!\n", argv[0]); } #endif #ifdef __TEE__ //In the case the ipfw do not tee the packet properly. #ifdef __DEBUG__ fprintf(stderr,"%s: Reinjecting diverted packet %i bytes\n", argv [0], data_len); #endif data_len = sendto(sock_fd, packet, data_len, 0, (struct sockaddr *)&sin, sinlen); #ifdef __DEBUG__ fprintf(stderr,"%s: %i bytes reinjected.\n", argv[0], data_len); #endif #endif //__TEE__ //Turn it into an outgoing package. If it already was, it's your mistake. sin.sin_addr.s_addr = INADDR_ANY; #ifdef __DEBUG__ fprintf(stderr,"%s: Reinjecting diverted packet %i bytes\n", argv [0], data_len); #endif data_len = sendto(sock_fd, packet, data_len, 0, (struct sockaddr *)&sin, sinlen); #ifdef __DEBUG__ fprintf(stderr,"%s: %i bytes reinjected.\n", argv[0], data_len); #endif #ifdef __DEBUG__ if (data_len <= 0) fprintf(stderr,"%s errno = %i\n", argv[0], errno); switch(errno) { //case EBADRQC: printf("errno = EBADRQC"); break; case ENETUNREACH: fprintf(stderr,"errno = ENETUNREACH"); break; default : break; } #endif } }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?B9D82A16-2113-45C7-9426-8F1A5EAA2032>