PDA

View Full Version : [Solved] Divert Socket Problem


yavuzg
January 22nd, 2010, 15:42
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
January 22nd, 2010, 18:08
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

yavuzg
January 22nd, 2010, 22:53
expl, thanks for the answer,

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

http://www.freebsd.org/cgi/man.cgi?query=divert&apropos=0&sektion=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
January 23rd, 2010, 02:21
Have you configured the kernel like its shown in the man page?

aragon
January 23rd, 2010, 06:53
And are you diverting traffic to your divert socket?

yavuzg
January 23rd, 2010, 13:41
@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
January 23rd, 2010, 14:02
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. This is how natd works. eg.


ipfw add 1000 divert 2000 tcp from any to any 2000

yavuzg
January 25th, 2010, 09:30
@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
January 25th, 2010, 09:57
@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
January 25th, 2010, 10:08
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 man page again and have a look at natd's source in /usr/src/sbin/natd.

yavuzg
January 25th, 2010, 10:17
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
January 25th, 2010, 14:23
I think my problem is in reinjecting packet back to IP stack.
I agree. Best would be to see how natd does it.

yavuzg
January 25th, 2010, 15:10
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..