Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 18 Feb 1998 22:51:06 +0500
From:      Konstantin Chuguev <joy@urc.ac.ru>
To:        freebsd-hackers@FreeBSD.ORG, freebsd-stable@FreeBSD.ORG
Subject:   Some problems with raw IP programming
Message-ID:  <34EB1F8A.A2543E68@urc.ac.ru>

next in thread | raw e-mail | index | archive | help
Hi, IP networking gurus :-)

Please help me to solve these problems:


I wrote a small daemon using tun* devices for IP-in-IP tunnel.
(Did not like any soft I saw before :-)

It works almost fine (under 2.2.5-STABLE), but has 3 problems.

1. I use connected sockets (i.e. bind() and connect()):
---
    struct in_addr local_ip, remote_ip ;
    int raw_ip, tunnel, max_fd ;
    struct sockaddr_in local_ipaddr, remote_ipaddr ;
    const int true = 1 ;

/* Initialization of local_ip and remote_ip with inet_aton() stripped... */

    raw_ip = socket( PF_INET, SOCK_RAW, IPPROTO_IPIP ) ;
    if( is_syserror( raw_ip < 0, LOG_ERR, "Can't open raw socket" ) )
        return ;
    if( is_syserror( setsockopt( raw_ip, SOL_SOCKET, SO_REUSEADDR, & true,
                                 sizeof( true ) ), LOG_WARNING,
                     "Can't reuse local address %s", local_addr ) )
        err_printf() ;
    remote_ipaddr.sin_family = AF_INET ;
    remote_ipaddr.sin_addr = remote_ip ;
    if( is_syserror( connect( raw_ip, (struct sockaddr *)(& remote_ipaddr),
                              sizeof( remote_ipaddr ) ), LOG_ERR,
                     "Can't connect to remote address %s", remote_addr ) )
        return ;
    local_ipaddr.sin_family = AF_INET ;
    local_ipaddr.sin_addr = local_ip ; 
    local_ipaddr.sin_port = 0 ;
    if( is_syserror( bind( raw_ip, (struct sockaddr *)(& local_ipaddr),
                           sizeof( local_ipaddr ) ), LOG_WARNING,
                     "Can't bind socket to local address %s", local_addr ) )
        err_printf() ;
---
Running the daemon, I get:
RR03:~# /usr/local/sbin/ipipd -i tun0 195.54.2.138 195.54.5.39
ipipd: Can't bind socket to local address 195.54.2.138: Can't assign requested
address
RR03:~#

This error has number 49 - EADDRNOTAVAIL. But:
RR03:~# ifconfig -a
sl0: flags=9011<UP,POINTOPOINT,LINK0,MULTICAST> mtu 552
        inet 195.54.2.138 --> 195.54.2.137 netmask 0xffffff00 

Now I just ignore this error, and all works. Since there is only one route
to the remote end of the tunnel, and it is through sl0 interface, I can be
sure that IPIP packets have the source address 195.54.2.138.
But if I have several possible routes (interfaces) from the local side
of the tunnel, then the router at the remote end may reject packets with
another source address :-(

The same picture with fxp0 interface.

Any suggestions?



2. When I receive IPIP (ICMP-in-IP, pinging through a tunnel) packets
from the raw socket:
---
            size = recv( raw_ip, buffer, sizeof( buffer ), 0 ) ;
            if( is_syserror( size < 0, LOG_CRIT, "Can't read from %s",
                             "raw socket" ) )
                return ;
            h_len = (unsigned)( ((struct ip *)buffer)->ip_hl ) << 2 ;
/*            log_printf( LOG_INFO, "Size=%d, ip_len=%d, h_len=%d\n",
                        size, ((struct ip *)buffer)->ip_len, h_len ) ; */
            size = write( tunnel, buffer + h_len,
                          /* ((struct ip *)buffer)->ip_len */ size - h_len ) ;
---
h_len is equal to 20 (the correct size of the IP packet without any options);
size (the result of recv() or read()) is equal to 104 (20 bytes for
     the envelope IP header, other 20 ones for the internal IP (ICMP) header,
     other 64 for the ICMP body);
the ICMP packet INSIDE the IPIP header looks pretty good, BUT:
((struct ip *)buffer)->ip_len is 84 !!! i.e. EXACTLY 20 less then
     the "size" variable and always EQUAL TO the size of the ENCLOSED IP
packet.

So I have to use "size - hlen" for writing packets into tun*, or
"((struct ip *)buffer)->ip_len", but not
"((struct ip *)buffer)->ip_len - hlen"

IP format description says the last should be correct, but it is not.



3. Sometimes (very seldom, can happen once a week), I get a message in syslog:

Feb 11 03:50:05 Chelyabinsk-RNOC-RR03 ipipd[6835]: Can't write to raw socket:
No
 buffer space available
or
Feb 18 22:13:45 Chelyabinsk-RNOC-RR03 ipipd[17393]: Can't write to raw socket:
N
o route to host

This is from the code:
---
            size = write( raw_ip, buffer, size ) ;
            if( is_syserror( size < 0, LOG_CRIT, "Can't write to %s",
                             "raw socket" ) )
            {
                err_printf() ;
                continue ;
            }
---
I ignore this error, preferring to lose a packet than to make a program more
complicate (now it is just one endless loop with select() inside).

But sometimes (even more seldom) that error causes the daemon to behave
strange:

Ping to the opposite side of the tunnel doesn't work.
When I tcpdump the tun0 interface, I see packets in both directions,
and I see the packets from the tunnel forwarded to other interfaces.
When I tcpdump the sl0 interface (through which the tunnel comes),
I see ONLY IPIP packets from the opposite side.

When I restart the daemon, all gets OK.

What can it be?

Sorry for so long questions :-)

Thanks.

--
	Konstantin V. Chuguev.		System administrator of
					Ural Regional Center of FREEnet,
	Joy@urc.ac.ru			Chelyabinsk, Russia.

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?34EB1F8A.A2543E68>