# Divert Socket Problem



## yavuzg (Jan 22, 2010)

Hi all,

I have problem with divert socket. I found some code for linux and compiled it in freebsd. What I want to simply print packages via divert socket. 

There is two files, server.pl and divert.c at below link.

server.pl simply open a connection and listens on a given port.


```
perl server.pl 2000
```

then I connect server via telnet


```
telnet myip 2000
```

and divert socket program is executed


```
./divert 2000
./divert:Creating a socket
./divert:Binding a socket
./divert: Waiting for data...
```

Although there is a connection between server and telnet, and I send some data via telnet, divert could not print any packages...

Any idea?


server.pl

```
#
#!/usr/bin/perl -w
#
 
use IO::Socket;
use Net::hostent;

my $port=shift || die "Usage server.pl <port>\n";

my $server = IO::Socket::INET->new( Proto => 'tcp',
LocalPort => $port,
Listen => SOMAXCONN,
Reuse => 1);
die "can't setup server" unless $server;

print "[Server $0 is running]\n";
 
while ($client = $server->accept()) {
         $client->autoflush(1);
         print $client "Welcome to $0\n type help to get a list of commands.\n";
         $hostinfo = gethostbyaddr($client->peeraddr);
         printf "[Connect from %s]\n", $hostinfo->name || $client->peerhost;
         print $client "[server]\$";
         while ( <$client>) {
                next unless /\S/; # blank line
                if (/quit|exit/i)
                {
                        last;
                }
                elsif (/date|time/i)
                {
                        printf $client "%s\n", scalar localtime;
                }
         }
         continue {
                 print $client "[server]\$ ";
         }
         close $client;
 }
```

divert.c


```
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <netinet/ip.h>
 
#define BUFSIZE 65535

char *progname;
int main(int argc, char** argv) {
        int fd,ret, n;
        struct sockaddr_in bindPort, sin;
        socklen_t sinlen;
        struct ip *hdr;
        unsigned char packet[BUFSIZE];
        int i;

        if (argc!=2) {
                fprintf(stderr, "Usage: %s <port number>\n", argv[0]);
                exit(1);
        }
        progname=argv[0];
        fprintf(stderr,"%s:Creating a socket\n",argv[0]);

        /* open a divert socket */
        fd=socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT);
 
        if (fd==-1) {
                perror("socket");
                exit(1);
        }

        bindPort.sin_family=PF_INET;
        bindPort.sin_port=htons(atol(argv[1]));
        bindPort.sin_addr.s_addr=0;
 
        fprintf(stderr,"%s:Binding a socket\n",argv[0]);

        ret=bind(fd, (struct sockaddr *)&bindPort, sizeof(struct sockaddr_in));

        if (ret!=0) {
                close(fd);
                fprintf(stderr, "%s: Error bind(): %s",argv[0],strerror(ret));
                exit(2);
        }

        printf("%s: Waiting for data...\n",argv[0]);

        /* read data in */
        sinlen=sizeof(struct sockaddr_in);

        while(1)
        {

                n=recvfrom(fd, packet, BUFSIZE, 0, (struct sockaddr *) &sin,&sinlen);
                hdr=(struct ip*)packet;
                printf("%s: The packet looks like this:\n",argv[0]);

                for( i=0; i<40; i++) {
                        printf("%02x ", (int)*(packet+i));
                        if (!((i+1)%16)) printf("\n");
                };

                printf("\n");

                printf("%s: Source address: %s\n",argv[0], inet_ntoa(hdr->ip_src));
                printf("%s: Destination address: %s\n", argv[0], inet_ntoa(hdr->ip_dst));
                printf("%s: Receiving IF address: %s\n", argv[0], inet_ntoa(sin.sin_addr));
                printf("%s: Protocol number: %i\n", argv[0], hdr->ip_p);
                /* reinjection */
                printf("%s Reinjecting DIVERT %i bytes\n", argv[0], n);
                n=sendto(fd, packet, n ,0, (struct sockaddr *) &sin, sinlen);
                printf("%s: %i bytes reinjected.\n", argv[0], n);

                if (n<=0)
                        printf("%s: Oops: errno = %i\n", argv[0], errno);
        }
}
```


----------



## expl (Jan 22, 2010)

FreeBSD "raw sockets" do not behave like on linux. Here is a brief description of what it does on FreeBSD:


> FreeBSD takes another approach. It *never* passes TCP or UDP packets to raw
> sockets. Such packets need to be read directly at the datalink layer by using
> libraries like libpcap or the bpf API. It also *never* passes any fragmented
> datagram. Each datagram has to be completeley reassembled before it is passed
> ...


----------



## yavuzg (Jan 22, 2010)

expl, thanks for the answer,

but instead of raw socket I used "divert" socket. 

http://www.freebsd.org/cgi/man.cgi?...ion=0&manpath=FreeBSD+8.0-RELEASE&format=html

http://www.faqs.org/docs/Linux-mini/Divert-Sockets-mini-HOWTO.html

What I understood from above links is that divert sockets can get, modify and reinject packets in network stack. 

"Incoming packets are diverted after reception on an IP interface, whereas outgoing packets are diverted before next hop forwarding."

Am I wrong?


----------



## expl (Jan 23, 2010)

Have you configured the kernel like its shown in the man page?


----------



## aragon (Jan 23, 2010)

And are you diverting traffic to your divert socket?


----------



## yavuzg (Jan 23, 2010)

@expl:
I have configured kernel and there is no problem. Code is running with no error. ( if kernel was not configured an error will be occured. )

@aragon:
what do you mean by diverting traffic to divert socket? Could you give an example?


----------



## aragon (Jan 23, 2010)

yavuzg said:
			
		

> what do you mean by diverting traffic to divert socket? Could you give an example?


Traffic needs to be diverted to the socket with ipfw(8).  This is how natd(8) works. eg.


```
ipfw add 1000 divert 2000 tcp from any to any 2000
```


----------



## yavuzg (Jan 25, 2010)

@argon, thanks for the answer.

I have added an ipfw rule as you said,
Now, I catch packets with divert socket but the new problem is telnet can't establish a connection to server program.

I think my ipfw rule and divert socket somehow blocks outgoing packets from server. Therefore connection timeout seen in telnet side. 

the rule I have added

```
ipfw add 1000 divert 2000 ip from any to any 2000
```

divert socket code output:

```
yavuzg# ./ipchains 2000                         
./ipchains:Creating a socket                    
./ipchains:Binding a socket                     
./ipchains: Waiting for data...                 
./ipchains: The packet looks like this:         
45 10 00 3c 17 be 40 00 40 06 00 00 c1 8c 5e 97 
c1 8c 5e 97 ee e2 07 d0 33 94 fd be 00 00 00 00 
a0 02 ff ff 61 24 00 00                         
./ipchains: Source address: 183.183.183.183      
./ipchains: Destination address: 183.183.183.183 
./ipchains: Receiving IF address: 127.0.0.1     
./ipchains: Protocol number: 6                  
./ipchains Reinjecting DIVERT 60 bytes          
./ipchains: 60 bytes reinjected.                
./ipchains: The packet looks like this:         
45 10 00 3c 17 bf 40 00 40 06 00 00 c1 8c 5e 97 
c1 8c 5e 97 ee e2 07 d0 33 94 fd be 00 00 00 00 
a0 02 ff ff 55 6b 00 00                         
./ipchains: Source address: 183.183.183.183      
./ipchains: Destination address: 183.183.183.183 
./ipchains: Receiving IF address: 127.0.0.1     
./ipchains: Protocol number: 6                  
./ipchains Reinjecting DIVERT 60 bytes          
./ipchains: 60 bytes reinjected.                
./ipchains: The packet looks like this:         
45 10 00 3c 17 c0 40 00 40 06 00 00 c1 8c 5e 97 
c1 8c 5e 97 ee e2 07 d0 33 94 fd be 00 00 00 00 
a0 02 ff ff 48 ea 00 00                         
./ipchains: Source address: 183.183.183.183      
./ipchains: Destination address: 183.183.183.183 
./ipchains: Receiving IF address: 127.0.0.1     
./ipchains: Protocol number: 6                  
./ipchains Reinjecting DIVERT 60 bytes          
./ipchains: 60 bytes reinjected.                
./ipchains: The packet looks like this:         
45 10 00 30 18 22 40 00 40 06 00 00 c1 8c 5e 97 
c1 8c 5e 97 ee e2 07 d0 33 94 fd be 00 00 00 00 
70 02 ff ff e1 ae 00 00                         
./ipchains: Source address: 183.183.183.183      
./ipchains: Destination address: 183.183.183.183 
./ipchains: Receiving IF address: 127.0.0.1     
./ipchains: Protocol number: 6                  
./ipchains Reinjecting DIVERT 48 bytes
```

telnet side:

```
telnet  183.183.183.183 2000
Trying  183.183.183.183...
telnet: connect to address  183.183.183.183: Operation timed out
telnet: Unable to connect to remote host
```


----------



## yavuzg (Jan 25, 2010)

yavuzg said:
			
		

> @argon, thanks for the answer.
> I think my ipfw rule and divert socket somehow blocks outgoing packets from server. Therefore connection timeout seen in telnet side.



or, I couldn't really reinject the packet to the IP stack.

Dou you have any idea about the origin or the problem?


----------



## aragon (Jan 25, 2010)

What else is in your ipfw ruleset?  Do you have a pass rule after the divert rule?

If that's not it then I don't know, sorry.  Check the divert(4) man page again and have a look at natd(8)'s source in /usr/src/sbin/natd.


----------



## yavuzg (Jan 25, 2010)

I have these rules:


```
yavuzg# ipfw list
01000 divert 2000 tcp from any to any dst-port 2000 in
01001 allow ip from any to any
65535 deny ip from any to any
```

When I delete 1000 from list, divert does not works but connection establishes 

I think my problem is in reinjecting packet back to IP stack. But couldn't figure out the problem yet...


----------



## aragon (Jan 25, 2010)

yavuzg said:
			
		

> I think my problem is in reinjecting packet back to IP stack.


I agree.  Best would be to see how natd(8) does it.


----------



## yavuzg (Jan 25, 2010)

I found the reason,

I were using client and server applications both on localhost,
when I tried to connect to server from another machine, divert socket worked as expected. 

I don't understand why it did not worked when both server and client on the same computer. It may be something related to loopback interface..


----------

