Possible FreeBSD Jail problem, or other bug in/with FreeRADIUS 2.0.0-pre2

Scott Lambert lambert at lambertfam.org
Tue Sep 18 01:57:20 CEST 2007


On Sun, Sep 16, 2007 at 06:46:34PM +0200, Alan DeKok wrote:
> Scott Lambert wrote:
> > In jailed client:
> > radclient: main: radclient_head->request->src_ipaddr.af = 0
> > radclient: main: client_ipaddr.ipaddr.ip4addr = 0, client_port = 0
> > lrad_socket: sa->sin_addr = 0
> > lrad_packet_list_socket_add: src.ss_family == AF_INET
> > lrad_packet_list_socket_add: ps->port = 64551
> > lrad_packet_list_socket_add: ps->inaddr_any = 0
> 
>   That should be 1, not 0.  Fix that, and everything else will be OK.
> Don't bother with printing anything in the packet comparison functions,
> or the hash functions.  They're just innocent bystanders.
> 
>   Figure out WHY lrad_packet_list_socket_add() isn't setting
> ps->inaddr_any to 1.  That's the only relevant issue.  Everything else
> is noise.

I'll do my best, but I'm way out in the deep end of the pool.  I'm
supposed to be over in the wading pool. :-)

I think I actually figured it out.  I used this reply to trace my logic
though the code, and it's probably not important to you, but I figured
I would leave it in just in case I'm wrong and maybe you could show me
where I went astray.  The fix that I've figured out should be attached
as src_lib_packet.c.diff.  It's a one character change so if it doesn't
make it through on the mailing list, it's not a big deal.

I do greatly appreciate your assistance with helping me to find the
right place to look.  I've learned more than I ever thought I would
need to know about how to make a network connection in C.  I'm just a
lowly System Administrator.  I usually just try to stay out of the real
programmers way.  Learning is always a good thing in my book.

Here is how I worked it through.

lrad_packet_list_socket_add() is called with a pointer to the radius
request packet list structure and the socket file descriptor of the
socket which has been created with the call to socket() and bound to an
IP and port by bind() during the prior call to lrad_socket().  Is that
correct?

>From radclient.c :
        /* 
         *      Bind to the first specified IP address and port.
         *      This means we ignore later ones.
         */
        if (radclient_head->request->src_ipaddr.af == AF_UNSPEC) {
                memset(&client_ipaddr, 0, sizeof(client_ipaddr));
                client_ipaddr.af = server_ipaddr.af;
                client_port = 0;
        } else {   
                client_ipaddr = radclient_head->request->src_ipaddr;
                client_port = radclient_head->request->src_port;
        }
        sockfd = lrad_socket(&client_ipaddr, client_port);

	/* I think this looks like:
	/* lrad_socket( client_ipaddr { .af=AF_INET, .ipaddr.ip4addr=0 }, client_port=0 ) */

        if (sockfd < 0) {
                fprintf(stderr, "radclient: socket: %s\n", librad_errstr);
                exit(1);
        }
                        
        pl = lrad_packet_list_create(1);
        if (!pl) {
                fprintf(stderr, "radclient: Out of memory\n");
                exit(1);
        }

        if (!lrad_packet_list_socket_add(pl, sockfd)) {
                fprintf(stderr, "radclient: Out of memory\n");
                exit(1);
        }


So the ipaddr_any is being set sometime during lrad_socket()?

lrad_socket() calls socket() with socket( AF_INET, SOCK_DGRAM, 0 )
because we are only dealing with ipv4 packets in this case.

Then, lrad_socket() fills in the sockaddr_in cast sockaddr_storage
structure, sa, aka salocal, based on data in lrad_ipaddr_t structure and
the port number which were passed as arguments to the function.

	sa->sin_family = AF_INET;
	sa->sin_addr = ipaddr->ipaddr.ip4addr;  /* aka 0 */
	sa->sin_port = htons((uint16_t) port);  /* aka 0 */ 


Then lrad_socket() calls bind() with that information which basically says:

"Hey Mr. OpSys, I need to talk to somebody on ipv4.  I really don't
care what IP and port.  Please just hook this socket file descriptor to
something."

lrad_socket() then returns the sockfd back to the radclient code which
sends that off to lrad_packet_list_socket_add().

lrad_packet_list_socket_add() creates a ps structure (packet socket?)
which it fills with information from the sockaddr_storage/sockaddr_in
structure pointed at by sockfd which was filled in/adjusted by the call
to bind(). ?

Since this is ipv4 we are going to refer to that sockaddr_in structure
as s4.

We set the ps->ipaddr.af = AF_INET.

We set ps->ipaddr.ipaddr.ip4addr = s4->sin_addr which is the jail's IP
address at this point.

We set ps->port = ntohs(s4->sin_port) which is some random high port
number.

I think the only place where ps->ipaddr_any is being set is when
we zero out the memory pointed to by ps.  The only place we change
that value is in the case where 
ps->ipaddr.ipaddr.ip4addr.s_addr == INADDR_ANY aka a 32bit 0 value.  

Tracking through the header files, it looks like
ps->ipaddr.ipaddr.ip4addr is the same memory location as
ps->ipaddr.ipaddr.ip4addr.s_addr, but that we might need to refer to
them individually for portability. 

s_addr is of type in_addr_t which is a typedef of uint32_t.  So I don't
think the cast below, which you suggested earlier, should be necessary,
on at least this platform.  The cast might be more necessary if we were
comparing ps->ipaddr.ipaddr.ip4addr to INADDR_ANY.  

if (*((uint32_t *) &ps->ipaddr.ipaddr.ip4addr.s_addr) == INADDR_ANY) {
                        ps->inaddr_any = 1;
}

So, should we be looking for != in the above if() from
lrad_packet_list_socket_add()?

I flipped that to a != comparison and it seems to work inside or outside
the jail with or without specifying the "Packet_Src-IP-Address".

Problem solved?  Or, is this going to break other things?

===================================
jail with Packet-Src-IP-Address:

radclient: main: radclient_head->request->src_ipaddr.af = 2
radclient: main: client_ipaddr.ipaddr.ip4addr = 460364101, client_port = 0
lrad_packet_list_socket_add: src.ss_family == AF_INET
lrad_packet_list_socket_add: ps->port = 61397
lrad_packet_list_socket_add: ps->inaddr_any = 0
lrad_packet_list_socket_add: ps->ipaddr.af = 2
lrad_packet_list_socket_add: ps->ipaddr.ipaddr.ip4addr = 460364101
lrad_packet_list_socket_add: ps->ipaddr.ipaddr.ip4addr.s_addr = 460364101
lrad_packet_list_socket_add: *((uint32_t *) &ps->ipaddr.ipaddr.ip4addr.s_addr) != INADDR_ANY
lrad_packet_list_socket_add: ps->inaddr_any = 1
Sending Access-Request of id 238 to 216.61.218.2 port 1645
        User-Name = "testuser1"
        User-Password = "testpass"
        NAS-IP-Address = 69.153.112.27
        NAS-Port = 1645
        Framed-Protocol = PPP
rad_recv: Access-Accept packet from host 216.61.218.2 port 1645, id=238, length=336
radclient: recv_one_packet: client_ipaddr.af = 2
radclient: recv_one_packet: client_ipaddr.ipaddr.ip4addr = 460364101
        Service-Type = Framed-User
        Framed-Protocol = PPP

===================================
jail without Packet-Src-IP-Address:

radclient: main: radclient_head->request->src_ipaddr.af = 0
radclient: main: client_ipaddr.ipaddr.ip4addr = 0, client_port = 0
lrad_packet_list_socket_add: src.ss_family == AF_INET
lrad_packet_list_socket_add: ps->port = 51670
lrad_packet_list_socket_add: ps->inaddr_any = 0
lrad_packet_list_socket_add: ps->ipaddr.af = 2
lrad_packet_list_socket_add: ps->ipaddr.ipaddr.ip4addr = 460364101
lrad_packet_list_socket_add: ps->ipaddr.ipaddr.ip4addr.s_addr = 460364101
lrad_packet_list_socket_add: *((uint32_t *) &ps->ipaddr.ipaddr.ip4addr.s_addr) != INADDR_ANY
lrad_packet_list_socket_add: ps->inaddr_any = 1
Sending Access-Request of id 236 to 216.61.218.2 port 1645
        User-Name = "testuser1"
        User-Password = "testpass"
        NAS-IP-Address = 69.153.112.27
        NAS-Port = 1645
        Framed-Protocol = PPP
rad_recv: Access-Accept packet from host 216.61.218.2 port 1645, id=236, length=336
radclient: recv_one_packet: client_ipaddr.af = 2
radclient: recv_one_packet: client_ipaddr.ipaddr.ip4addr = 0
        Service-Type = Framed-User
        Framed-Protocol = PPP

===================================
host without Packet-Src-IP-Address:

radclient: main: radclient_head->request->src_ipaddr.af = 0
radclient: main: client_ipaddr.ipaddr.ip4addr = 0, client_port = 0
lrad_packet_list_socket_add: src.ss_family == AF_INET
lrad_packet_list_socket_add: ps->port = 54700
lrad_packet_list_socket_add: ps->inaddr_any = 0
lrad_packet_list_socket_add: ps->ipaddr.af = 2
lrad_packet_list_socket_add: ps->ipaddr.ipaddr.ip4addr = 0
lrad_packet_list_socket_add: ps->ipaddr.ipaddr.ip4addr.s_addr = 0
lrad_packet_list_socket_add: *((uint32_t *) &ps->ipaddr.ipaddr.ip4addr.s_addr) == INADDR_ANY
lrad_packet_list_socket_add: ps->inaddr_any = 0
Sending Access-Request of id 67 to 216.61.218.2 port 1645
        User-Name = "testuser1"
        User-Password = "testpass"
        NAS-IP-Address = 69.153.112.27
        NAS-Port = 1645
        Framed-Protocol = PPP
rad_recv: Access-Accept packet from host 216.61.218.2 port 1645, id=67, length=336
radclient: recv_one_packet: client_ipaddr.af = 2
radclient: recv_one_packet: client_ipaddr.ipaddr.ip4addr = 0
        Service-Type = Framed-User
        Framed-Protocol = PPP

-- 
Scott Lambert                    KC5MLE                       Unix SysAdmin
lambert at lambertfam.org

-------------- next part --------------
diff -ruN freeradius-server-snapshot-20070912/src/lib/packet.c freeradius-server-snapshot/src/lib/packet.c
--- freeradius-server-snapshot-20070912/src/lib/packet.c	Tue Sep 11 19:11:57 2007
+++ freeradius-server-snapshot/src/lib/packet.c	Mon Sep 17 18:34:42 2007
@@ -383,7 +383,7 @@
 		ps->ipaddr.ipaddr.ip4addr = s4->sin_addr;
 		ps->port = ntohs(s4->sin_port);
 
-		if (ps->ipaddr.ipaddr.ip4addr.s_addr == INADDR_ANY) {
+		if (ps->ipaddr.ipaddr.ip4addr.s_addr != INADDR_ANY) {
 			ps->inaddr_any = 1;
 		}
 


More information about the Freeradius-Users mailing list