Divert Socket Problem

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.

Code:
perl server.pl 2000

then I connect server via telnet

Code:
telnet myip 2000

and divert socket program is executed

Code:
./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
Code:
#
#!/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

Code:
#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);
        }
}
 
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
to a raw socket.

FreeBSD passes to a raw socket:
a) every IP datagram with a protocol field that is not registered in
the kernel
b) all IGMP packets after kernel finishes processing them
c) all ICMP packets (except echo request, timestamp request and address
mask request) after kernel finishes processes them
 
@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?
 
@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
Code:
ipfw add 1000 divert 2000 ip from any to any 2000

divert socket code output:
Code:
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:
Code:
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 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?
 
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.
 
I have these rules:

Code:
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...
 
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..
 
Back
Top