Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/networking/udhcp/dhcprelay.c

    r1765 r2725  
    22/* Port to Busybox Copyright (C) 2006 Jesse Dutton <jessedutton@gmail.com>
    33 *
    4  * Licensed under GPL v2, see file LICENSE in this tarball for details.
     4 * Licensed under GPLv2, see file LICENSE in this source tree.
    55 *
    66 * DHCP Relay for 'DHCPv4 Configuration of IPSec Tunnel Mode' support
     
    1010 * Upstream has GPL v2 or later
    1111 */
    12 
    1312#include "common.h"
    14 #include "dhcpd.h"
    15 #include "options.h"
    16 
    17 /* constants */
    18 #define SELECT_TIMEOUT 5 /* select timeout in sec. */
    19 #define MAX_LIFETIME 2*60 /* lifetime of an xid entry in sec. */
    20 #define MAX_INTERFACES 9
    21 
     13
     14#define SERVER_PORT    67
     15
     16/* lifetime of an xid entry in sec. */
     17#define MAX_LIFETIME   2*60
     18/* select timeout in sec. */
     19#define SELECT_TIMEOUT (MAX_LIFETIME / 8)
    2220
    2321/* This list holds information about clients. The xid_* functions manipulate this list. */
    24 static struct xid_item {
     22struct xid_item {
     23    unsigned timestamp;
     24    int client;
    2525    uint32_t xid;
    2626    struct sockaddr_in ip;
    27     int client;
    28     time_t timestamp;
    2927    struct xid_item *next;
    30 } dhcprelay_xid_list = {0, {0}, 0, 0, NULL};
    31 
     28};
     29
     30#define dhcprelay_xid_list (*(struct xid_item*)&bb_common_bufsiz1)
    3231
    3332static struct xid_item *xid_add(uint32_t xid, struct sockaddr_in *ip, int client)
     
    4241    item->xid = xid;
    4342    item->client = client;
    44     item->timestamp = time(NULL);
     43    item->timestamp = monotonic_sec();
    4544    item->next = dhcprelay_xid_list.next;
    4645    dhcprelay_xid_list.next = item;
     
    5352    struct xid_item *item = dhcprelay_xid_list.next;
    5453    struct xid_item *last = &dhcprelay_xid_list;
    55     time_t current_time = time(NULL);
     54    unsigned current_time = monotonic_sec();
    5655
    5756    while (item != NULL) {
     
    7271    while (item != NULL) {
    7372        if (item->xid == xid) {
    74             return item;
     73            break;
    7574        }
    7675        item = item->next;
    7776    }
    78     return NULL;
     77    return item;
    7978}
    8079
     
    10099 * returns the message type on success, -1 otherwise
    101100 */
    102 static int get_dhcp_packet_type(struct dhcpMessage *p)
     101static int get_dhcp_packet_type(struct dhcp_packet *p)
    103102{
    104103    uint8_t *op;
     
    108107        return -1;
    109108    /* get message type option */
    110     op = get_option(p, DHCP_MESSAGE_TYPE);
     109    op = udhcp_get_option(p, DHCP_MESSAGE_TYPE);
    111110    if (op != NULL)
    112111        return op[0];
     
    115114
    116115/**
    117  * signal_handler - handles signals ;-)
    118  * sig - sent signal
    119  */
    120 static smallint dhcprelay_stopflag;
    121 
    122 static void dhcprelay_signal_handler(int sig)
    123 {
    124     dhcprelay_stopflag = 1;
    125 }
    126 
    127 /**
    128  * get_client_devices - parses the devices list
    129  * dev_list - comma separated list of devices
     116 * make_iface_list - parses client/server interface names
    130117 * returns array
    131118 */
    132 static char **get_client_devices(char *dev_list, int *client_number)
    133 {
    134     char *s, *list, **client_dev;
     119static char **make_iface_list(char **client_and_server_ifaces, int *client_number)
     120{
     121    char *s, **iface_list;
    135122    int i, cn;
    136123
    137     /* copy list */
    138     list = xstrdup(dev_list);
    139     if (list == NULL) return NULL;
    140 
    141124    /* get number of items */
    142     for (s = dev_list, cn = 1; *s; s++)
     125    cn = 2; /* 1 server iface + at least 1 client one */
     126    s = client_and_server_ifaces[0]; /* list of client ifaces */
     127    while (*s) {
    143128        if (*s == ',')
    144129            cn++;
    145 
    146     client_dev = xzalloc(cn * sizeof(*client_dev));
    147 
    148     /* parse list */
    149     s = strtok(list, ",");
    150     i = 0;
    151     while (s != NULL) {
    152         client_dev[i++] = xstrdup(s);
    153         s = strtok(NULL, ",");
    154     }
    155 
    156     /* free copy and exit */
    157     free(list);
     130        s++;
     131    }
    158132    *client_number = cn;
    159     return client_dev;
    160 }
    161 
    162 
    163 /* Creates listen sockets (in fds) and returns the number allocated. */
    164 static int init_sockets(char **client, int num_clients,
    165             char *server, int *fds, int *max_socket)
    166 {
    167     int i;
    168 
    169     /* talk to real server on bootps */
    170     fds[0] = listen_socket(/*INADDR_ANY,*/ 67, server);
    171     *max_socket = fds[0];
    172 
    173     /* array starts at 1 since server is 0 */
    174     num_clients++;
    175 
    176     for (i = 1; i < num_clients; i++) {
    177         /* listen for clients on bootps */
    178         fds[i] = listen_socket(/*NADDR_ANY,*/ 67, client[i-1]);
    179         if (fds[i] > *max_socket)
    180             *max_socket = fds[i];
    181     }
    182 
    183     return i;
    184 }
    185 
     133
     134    /* create vector of pointers */
     135    iface_list = xzalloc(cn * sizeof(iface_list[0]));
     136
     137    iface_list[0] = client_and_server_ifaces[1]; /* server iface */
     138
     139    i = 1;
     140    s = xstrdup(client_and_server_ifaces[0]); /* list of client ifaces */
     141    goto store_client_iface_name;
     142
     143    while (i < cn) {
     144        if (*s++ == ',') {
     145            s[-1] = '\0';
     146 store_client_iface_name:
     147            iface_list[i++] = s;
     148        }
     149    }
     150
     151    return iface_list;
     152}
     153
     154/* Creates listen sockets (in fds) bound to client and server ifaces,
     155 * and returns numerically max fd.
     156 */
     157static int init_sockets(char **iface_list, int num_clients, int *fds)
     158{
     159    int i, n;
     160
     161    n = 0;
     162    for (i = 0; i < num_clients; i++) {
     163        fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, iface_list[i]);
     164        if (n < fds[i])
     165            n = fds[i];
     166    }
     167    return n;
     168}
     169
     170static int sendto_ip4(int sock, const void *msg, int msg_len, struct sockaddr_in *to)
     171{
     172    int err;
     173
     174    errno = 0;
     175    err = sendto(sock, msg, msg_len, 0, (struct sockaddr*) to, sizeof(*to));
     176    err -= msg_len;
     177    if (err)
     178        bb_perror_msg("sendto");
     179    return err;
     180}
    186181
    187182/**
    188  * pass_on() - forwards dhcp packets from client to server
     183 * pass_to_server() - forwards dhcp packets from client to server
    189184 * p - packet to send
    190185 * client - number of the client
    191186 */
    192 static void pass_on(struct dhcpMessage *p, int packet_len, int client, int *fds,
     187static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, int *fds,
    193188            struct sockaddr_in *client_addr, struct sockaddr_in *server_addr)
    194189{
    195     int res, type;
    196     struct xid_item *item;
     190    int type;
    197191
    198192    /* check packet_type */
     
    206200
    207201    /* create new xid entry */
    208     item = xid_add(p->xid, client_addr, client);
    209 
    210     /* forward request to LAN (server) */
    211     res = sendto(fds[0], p, packet_len, 0, (struct sockaddr*)server_addr,
    212             sizeof(struct sockaddr_in));
    213     if (res != packet_len) {
    214         bb_perror_msg("pass_on");
    215         return;
    216     }
     202    xid_add(p->xid, client_addr, client);
     203
     204    /* forward request to server */
     205    /* note that we send from fds[0] which is bound to SERVER_PORT (67).
     206     * IOW: we send _from_ SERVER_PORT! Although this may look strange,
     207     * RFC 1542 not only allows, but prescribes this for BOOTP relays.
     208     */
     209    sendto_ip4(fds[0], p, packet_len, server_addr);
    217210}
    218211
    219212/**
    220  * pass_back() - forwards dhcp packets from server to client
     213 * pass_to_client() - forwards dhcp packets from server to client
    221214 * p - packet to send
    222215 */
    223 static void pass_back(struct dhcpMessage *p, int packet_len, int *fds)
    224 {
    225     int res, type;
     216static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds)
     217{
     218    int type;
    226219    struct xid_item *item;
    227220
     
    238231    }
    239232
     233//TODO: also do it if (p->flags & htons(BROADCAST_FLAG)) is set!
    240234    if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY))
    241235        item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST);
    242     if (item->client > MAX_INTERFACES)
    243         return;
    244     res = sendto(fds[item->client], p, packet_len, 0, (struct sockaddr*)(&item->ip),
    245                 sizeof(item->ip));
    246     if (res != packet_len) {
    247         bb_perror_msg("pass_back");
    248         return;
     236
     237    if (sendto_ip4(fds[item->client], p, packet_len, &item->ip) != 0) {
     238        return; /* send error occurred */
    249239    }
    250240
     
    253243}
    254244
    255 static void dhcprelay_loop(int *fds, int num_sockets, int max_socket, char **clients,
    256         struct sockaddr_in *server_addr, uint32_t gw_ip)
    257 {
    258     struct dhcpMessage dhcp_msg;
    259     fd_set rfds;
    260     size_t packlen;
    261     socklen_t addr_size;
    262     struct sockaddr_in client_addr;
    263     struct timeval tv;
    264     int i;
    265 
    266     while (!dhcprelay_stopflag) {
     245int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     246int dhcprelay_main(int argc, char **argv)
     247{
     248    struct sockaddr_in server_addr;
     249    char **iface_list;
     250    int *fds;
     251    int num_sockets, max_socket;
     252    uint32_t our_nip;
     253
     254    server_addr.sin_family = AF_INET;
     255    server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
     256    server_addr.sin_port = htons(SERVER_PORT);
     257
     258    /* dhcprelay CLIENT_IFACE1[,CLIENT_IFACE2...] SERVER_IFACE [SERVER_IP] */
     259    if (argc == 4) {
     260        if (!inet_aton(argv[3], &server_addr.sin_addr))
     261            bb_perror_msg_and_die("bad server IP");
     262    } else if (argc != 3) {
     263        bb_show_usage();
     264    }
     265
     266    iface_list = make_iface_list(argv + 1, &num_sockets);
     267
     268    fds = xmalloc(num_sockets * sizeof(fds[0]));
     269
     270    /* Create sockets and bind one to every iface */
     271    max_socket = init_sockets(iface_list, num_sockets, fds);
     272
     273    /* Get our IP on server_iface */
     274    if (udhcp_read_interface(argv[2], NULL, &our_nip, NULL))
     275        return 1;
     276
     277    /* Main loop */
     278    while (1) {
     279// reinit stuff from time to time? go back to make_iface_list
     280// every N minutes?
     281        fd_set rfds;
     282        struct timeval tv;
     283        int i;
     284
    267285        FD_ZERO(&rfds);
    268286        for (i = 0; i < num_sockets; i++)
     
    271289        tv.tv_usec = 0;
    272290        if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) {
     291            int packlen;
     292            struct dhcp_packet dhcp_msg;
     293
    273294            /* server */
    274295            if (FD_ISSET(fds[0], &rfds)) {
    275                 packlen = udhcp_get_packet(&dhcp_msg, fds[0]);
     296                packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]);
    276297                if (packlen > 0) {
    277                     pass_back(&dhcp_msg, packlen, fds);
     298                    pass_to_client(&dhcp_msg, packlen, fds);
    278299                }
    279300            }
     301
     302            /* clients */
    280303            for (i = 1; i < num_sockets; i++) {
    281                 /* clients */
     304                struct sockaddr_in client_addr;
     305                socklen_t addr_size;
     306
    282307                if (!FD_ISSET(fds[i], &rfds))
    283308                    continue;
    284                 addr_size = sizeof(struct sockaddr_in);
     309
     310                addr_size = sizeof(client_addr);
    285311                packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0,
    286                             (struct sockaddr *)(&client_addr), &addr_size);
     312                        (struct sockaddr *)(&client_addr), &addr_size);
    287313                if (packlen <= 0)
    288314                    continue;
    289                 if (read_interface(clients[i-1], NULL, &dhcp_msg.giaddr, NULL))
    290                     dhcp_msg.giaddr = gw_ip;
    291                 pass_on(&dhcp_msg, packlen, i, fds, &client_addr, server_addr);
     315
     316                /* Get our IP on corresponding client_iface */
     317// RFC 1542
     318// 4.1 General BOOTP Processing for Relay Agents
     319// 4.1.1 BOOTREQUEST Messages
     320//   If the relay agent does decide to relay the request, it MUST examine
     321//   the 'giaddr' ("gateway" IP address) field.  If this field is zero,
     322//   the relay agent MUST fill this field with the IP address of the
     323//   interface on which the request was received.  If the interface has
     324//   more than one IP address logically associated with it, the relay
     325//   agent SHOULD choose one IP address associated with that interface and
     326//   use it consistently for all BOOTP messages it relays.  If the
     327//   'giaddr' field contains some non-zero value, the 'giaddr' field MUST
     328//   NOT be modified.  The relay agent MUST NOT, under any circumstances,
     329//   fill the 'giaddr' field with a broadcast address as is suggested in
     330//   [1] (Section 8, sixth paragraph).
     331
     332// but why? what if server can't route such IP? Client ifaces may be, say, NATed!
     333
     334// 4.1.2 BOOTREPLY Messages
     335//   BOOTP relay agents relay BOOTREPLY messages only to BOOTP clients.
     336//   It is the responsibility of BOOTP servers to send BOOTREPLY messages
     337//   directly to the relay agent identified in the 'giaddr' field.
     338// (yeah right, unless it is impossible... see comment above)
     339//   Therefore, a relay agent may assume that all BOOTREPLY messages it
     340//   receives are intended for BOOTP clients on its directly-connected
     341//   networks.
     342//
     343//   When a relay agent receives a BOOTREPLY message, it should examine
     344//   the BOOTP 'giaddr', 'yiaddr', 'chaddr', 'htype', and 'hlen' fields.
     345//   These fields should provide adequate information for the relay agent
     346//   to deliver the BOOTREPLY message to the client.
     347//
     348//   The 'giaddr' field can be used to identify the logical interface from
     349//   which the reply must be sent (i.e., the host or router interface
     350//   connected to the same network as the BOOTP client).  If the content
     351//   of the 'giaddr' field does not match one of the relay agent's
     352//   directly-connected logical interfaces, the BOOTREPLY messsage MUST be
     353//   silently discarded.
     354                if (udhcp_read_interface(iface_list[i], NULL, &dhcp_msg.gateway_nip, NULL)) {
     355                    /* Fall back to our IP on server iface */
     356// this makes more sense!
     357                    dhcp_msg.gateway_nip = our_nip;
     358                }
     359// maybe dhcp_msg.hops++? drop packets with too many hops (RFC 1542 says 4 or 16)?
     360                pass_to_server(&dhcp_msg, packlen, i, fds, &client_addr, &server_addr);
    292361            }
    293362        }
    294363        xid_expire();
    295     }
    296 }
    297 
    298 int dhcprelay_main(int argc, char **argv);
    299 int dhcprelay_main(int argc, char **argv)
    300 {
    301     int i, num_sockets, max_socket, fds[MAX_INTERFACES];
    302     uint32_t gw_ip;
    303     char **clients;
    304     struct sockaddr_in server_addr;
    305 
    306     server_addr.sin_family = AF_INET;
    307     server_addr.sin_port = htons(67);
    308     if (argc == 4) {
    309         if (!inet_aton(argv[3], &server_addr.sin_addr))
    310             bb_perror_msg_and_die("didn't grok server");
    311     } else if (argc == 3) {
    312         server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
    313     } else {
    314         bb_show_usage();
    315     }
    316     clients = get_client_devices(argv[1], &num_sockets);
    317     if (!clients) return 0;
    318 
    319     signal(SIGTERM, dhcprelay_signal_handler);
    320     signal(SIGQUIT, dhcprelay_signal_handler);
    321     signal(SIGINT, dhcprelay_signal_handler);
    322 
    323     num_sockets = init_sockets(clients, num_sockets, argv[2], fds, &max_socket);
    324 
    325     if (read_interface(argv[2], NULL, &gw_ip, NULL))
    326         return 1;
    327 
    328     dhcprelay_loop(fds, num_sockets, max_socket, clients, &server_addr, gw_ip);
    329 
    330     if (ENABLE_FEATURE_CLEAN_UP) {
    331         for (i = 0; i < num_sockets; i++) {
    332             close(fds[i]);
    333             free(clients[i]);
    334         }
    335     }
    336 
    337     return 0;
    338 }
     364    } /* while (1) */
     365
     366    /* return 0; - not reached */
     367}
Note: See TracChangeset for help on using the changeset viewer.