~ubuntu-branches/ubuntu/natty/freeradius/natty-updates

« back to all changes in this revision

Viewing changes to src/lib/packet.c

  • Committer: Bazaar Package Importer
  • Author(s): Josip Rodin
  • Date: 2009-11-23 03:57:37 UTC
  • mfrom: (1.2.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 28.
  • Revision ID: james.westby@ubuntu.com-20091123035737-zsgtzhfych8hir68
Tags: 2.1.7+dfsg-1
* Adopting the package, closes: #536623.
* New upstream version, closes: #513484.
  + Fixes the blooper in unlang evaluation logic, closes: #526175.
* Used quilt (and added README.source), and moved upstream file patching
  into debian/patches/. The source is no longer in collab-maint git
  (to make it simpler for me to finally get this out the door), but
  kept the .gitignore should we need that again.
* Dropped the dialup_admin/bin/backup_radacct patch (integrated upstream).
* Dropped the raddb/Makefile patch (problem no longer exists upstream).
* Dropped the lib/packet.c lib/radius.c main/listen.c patches (was from
  upstream 2.0.5 anyway).
* Dropped references to otp.conf, it no longer exists upstream.
  Keep removing the conffile statoverride in prerm.
* Dropped references to snmp.conf, it no longer exists upstream.
  Keep removing the conffile statoverride in prerm.
* Ship /etc/freeradius/modules/* in the freeradius package.
* Stop shipping sites-enabled symlinks in the package and instead create
  them only on initial install, thanks to Matej Vela, closes: #533396.
* Add export PATH="${PATH:+$PATH:}/usr/sbin:/sbin" to the init script
  at the request of John Morrissey, closes: #550143.
* Stop installing /var/run/freeradius in the package to silence Lintian.
  The init script already recreates it at will.
* Remove executable bit from example.pl to silence Lintian.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * packet.c     Generic packet manipulation functions.
3
3
 *
4
 
 * Version:     $Id: packet.c,v 1.21 2008/05/29 15:00:54 aland Exp $
 
4
 * Version:     $Id$
5
5
 *
6
6
 *   This library is free software; you can redistribute it and/or
7
7
 *   modify it under the terms of the GNU Lesser General Public
21
21
 */
22
22
 
23
23
#include        <freeradius-devel/ident.h>
24
 
RCSID("$Id: packet.c,v 1.21 2008/05/29 15:00:54 aland Exp $")
 
24
RCSID("$Id$")
25
25
 
26
26
#include        <freeradius-devel/libradius.h>
27
27
 
175
175
int fr_socket(fr_ipaddr_t *ipaddr, int port)
176
176
{
177
177
        int sockfd;
178
 
        uint16_t sport;
179
178
        struct sockaddr_storage salocal;
180
179
        socklen_t       salen;
181
180
 
182
181
        if ((port < 0) || (port > 65535)) {
183
 
                librad_log("Port %d is out of allowed bounds", port);
 
182
                fr_strerror_printf("Port %d is out of allowed bounds", port);
184
183
                return -1;
185
184
        }
186
185
 
187
186
        sockfd = socket(ipaddr->af, SOCK_DGRAM, 0);
188
187
        if (sockfd < 0) {
189
 
                librad_log("cannot open socket: %s", strerror(errno));
 
188
                fr_strerror_printf("cannot open socket: %s", strerror(errno));
190
189
                return sockfd;
191
190
        }
192
191
 
196
195
         */
197
196
        if (udpfromto_init(sockfd) != 0) {
198
197
                close(sockfd);
199
 
                librad_log("cannot initialize udpfromto: %s", strerror(errno));
 
198
                fr_strerror_printf("cannot initialize udpfromto: %s", strerror(errno));
200
199
                return -1;
201
200
        }
202
201
#endif
203
202
 
204
 
        sport = port;
205
 
        sport = htons(sport);
206
 
        memset(&salocal, 0, sizeof(salocal));
207
 
        if (ipaddr->af == AF_INET) {
208
 
                struct sockaddr_in s4;
209
203
 
210
 
                s4.sin_family = AF_INET;
211
 
                s4.sin_addr = ipaddr->ipaddr.ip4addr;
212
 
                s4.sin_port = sport;
213
 
                salen = sizeof(s4);
214
 
                memset(&salocal, 0, sizeof(salocal));
215
 
                memcpy(&salocal, &s4, salen);
 
204
        if (!fr_ipaddr2sockaddr(ipaddr, port, &salocal, &salen)) {
 
205
                return sockfd;
 
206
        }
216
207
 
217
208
#ifdef HAVE_STRUCT_SOCKADDR_IN6
218
 
        } else if (ipaddr->af == AF_INET6) {
219
 
                struct sockaddr_in6 s6;
220
 
 
221
 
                s6.sin6_family = AF_INET6;
222
 
                s6.sin6_addr = ipaddr->ipaddr.ip6addr;
223
 
                s6.sin6_port = sport;
224
 
                salen = sizeof(s6);
225
 
                memset(&salocal, 0, sizeof(salocal));
226
 
                memcpy(&salocal, &s6, salen);
227
 
 
228
 
#if 1
 
209
        if (ipaddr->af == AF_INET6) {
229
210
                /*
230
211
                 *      Listening on '::' does NOT get you IPv4 to
231
212
                 *      IPv6 mapping.  You've got to listen on an IPv4
241
222
                                   (char *)&on, sizeof(on));
242
223
                }
243
224
#endif /* IPV6_V6ONLY */
244
 
#endif
 
225
        }
245
226
#endif /* HAVE_STRUCT_SOCKADDR_IN6 */
246
 
        } else {
247
 
                return sockfd;  /* don't bind it */
 
227
 
 
228
        if (ipaddr->af == AF_INET) {
 
229
                UNUSED int flag;
 
230
                
 
231
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
 
232
                /*
 
233
                 *      Disable PMTU discovery.  On Linux, this
 
234
                 *      also makes sure that the "don't fragment"
 
235
                 *      flag is zero.
 
236
                 */
 
237
                flag = IP_PMTUDISC_DONT;
 
238
                setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER,
 
239
                           &flag, sizeof(flag));
 
240
#endif
 
241
 
 
242
#if defined(IP_DONTFRAG)
 
243
                /*
 
244
                 *      Ensure that the "don't fragment" flag is zero.
 
245
                 */
 
246
                flag = 0;
 
247
                setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG,
 
248
                           &flag, sizeof(flag));
 
249
#endif
248
250
        }
249
251
 
250
252
        if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
251
253
                close(sockfd);
252
 
                librad_log("cannot bind socket: %s", strerror(errno));
 
254
                fr_strerror_printf("cannot bind socket: %s", strerror(errno));
253
255
                return -1;
254
256
        }
255
257
 
380
382
                return 0;
381
383
        }
382
384
 
 
385
        if (!fr_sockaddr2ipaddr(&src, sizeof_src, &ps->ipaddr, &ps->port)) {
 
386
                return 0;
 
387
        }
 
388
 
383
389
        /*
384
390
         *      Grab IP addresses & ports from the sockaddr.
385
391
         */
386
 
        ps->ipaddr.af = src.ss_family;
387
392
        if (src.ss_family == AF_INET) {
388
 
                struct sockaddr_in      s4;
389
 
 
390
 
                memcpy(&s4, &src, sizeof(s4));
391
 
                ps->ipaddr.ipaddr.ip4addr = s4.sin_addr;
392
 
                ps->port = ntohs(s4.sin_port);
393
 
 
394
393
                if (ps->ipaddr.ipaddr.ip4addr.s_addr == INADDR_ANY) {
395
394
                        ps->inaddr_any = 1;
396
395
                }
397
396
 
398
397
#ifdef HAVE_STRUCT_SOCKADDR_IN6
399
398
        } else if (src.ss_family == AF_INET6) {
400
 
                struct sockaddr_in6     s6;
401
 
 
402
 
                memcpy(&s6, &src, sizeof(s6));
403
 
                ps->ipaddr.ipaddr.ip6addr = s6.sin6_addr;
404
 
                ps->port = ntohs(s6.sin6_port);
405
 
 
406
399
                if (IN6_IS_ADDR_UNSPECIFIED(&ps->ipaddr.ipaddr.ip6addr)) {
407
400
                        ps->inaddr_any = 1;
408
401
                }
638
631
int fr_packet_list_id_alloc(fr_packet_list_t *pl,
639
632
                              RADIUS_PACKET *request)
640
633
{
641
 
        int i, id, start;
 
634
        int i, id, start, fd;
642
635
        uint32_t free_mask;
643
636
        fr_packet_dst2id_t my_pd, *pd;
644
637
        fr_packet_socket_t *ps;
678
671
        id = start = (int) fr_rand() & 0xff;
679
672
 
680
673
        while (pd->id[id] == pl->mask) { /* all sockets are using this ID */
 
674
        redo:
681
675
                id++;
682
676
                id &= 0xff;
683
677
                if (id == start) return 0;
685
679
 
686
680
        free_mask = ~((~pd->id[id]) & pl->mask);
687
681
 
688
 
        start = -1;
 
682
        /*
 
683
         *      This ID has at least one socket free.  Check the sockets
 
684
         *      to see if they are satisfactory for the caller.
 
685
         */
 
686
        fd = -1;
689
687
        for (i = 0; i < MAX_SOCKETS; i++) {
690
688
                if (pl->sockets[i].sockfd == -1) continue; /* paranoia */
691
689
 
692
 
                if ((free_mask & (1 << i)) == 0) {
693
 
                        start = i;
694
 
                        break;
695
 
                }
696
 
        }
697
 
 
698
 
        if (start < 0) return 0; /* bad error */
699
 
 
700
 
        pd->id[id] |= (1 << start);
701
 
        ps = &pl->sockets[start];
 
690
                /*
 
691
                 *      This ID is allocated.
 
692
                 */
 
693
                if ((free_mask & (1 << i)) != 0) continue;
 
694
                
 
695
                /*
 
696
                 *      If the caller cares about the source address,
 
697
                 *      try to re-use that.  This means that the
 
698
                 *      requested source address is set, AND this
 
699
                 *      socket wasn't bound to "*", AND the requested
 
700
                 *      source address is the same as this socket
 
701
                 *      address.
 
702
                 */
 
703
                if ((request->src_ipaddr.af != AF_UNSPEC) &&
 
704
                    !pl->sockets[i].inaddr_any &&
 
705
                    (fr_ipaddr_cmp(&request->src_ipaddr, &pl->sockets[i].ipaddr) != 0)) continue;
 
706
 
 
707
                /*
 
708
                 *      They asked for a specific address, and this socket
 
709
                 *      is bound to a wildcard address.  Ignore this one, too.
 
710
                 */
 
711
                if ((request->src_ipaddr.af != AF_UNSPEC) &&
 
712
                    pl->sockets[i].inaddr_any) continue;
 
713
                
 
714
                fd = i;
 
715
                break;
 
716
        }
 
717
 
 
718
        if (fd < 0) {
 
719
                goto redo; /* keep searching IDs */
 
720
        }
 
721
 
 
722
        pd->id[id] |= (1 << fd);
 
723
        ps = &pl->sockets[fd];
702
724
 
703
725
        ps->num_outgoing++;
704
726
        pl->num_outgoing++;