Ignore:
Timestamp:
Jan 1, 2014, 12:47:38 AM (12 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.21.1
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/3.2/mindi-busybox/networking/udhcp/dhcpc.c

    r2725 r3232  
    2626#include "dhcpc.h"
    2727
    28 #include <asm/types.h>
    29 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
    30 # include <netpacket/packet.h>
    31 # include <net/ethernet.h>
    32 #else
    33 # include <linux/if_packet.h>
    34 # include <linux/if_ether.h>
     28#include <netinet/if_ether.h>
     29#include <linux/filter.h>
     30#include <linux/if_packet.h>
     31
     32/* "struct client_config_t client_config" is in bb_common_bufsiz1 */
     33
     34
     35#if ENABLE_LONG_OPTS
     36static const char udhcpc_longopts[] ALIGN1 =
     37    "clientid-none\0"  No_argument       "C"
     38    "vendorclass\0"    Required_argument "V"
     39    "hostname\0"       Required_argument "H"
     40    "fqdn\0"           Required_argument "F"
     41    "interface\0"      Required_argument "i"
     42    "now\0"            No_argument       "n"
     43    "pidfile\0"        Required_argument "p"
     44    "quit\0"           No_argument       "q"
     45    "release\0"        No_argument       "R"
     46    "request\0"        Required_argument "r"
     47    "script\0"         Required_argument "s"
     48    "timeout\0"        Required_argument "T"
     49    "retries\0"        Required_argument "t"
     50    "tryagain\0"       Required_argument "A"
     51    "syslog\0"         No_argument       "S"
     52    "request-option\0" Required_argument "O"
     53    "no-default-options\0" No_argument   "o"
     54    "foreground\0"     No_argument       "f"
     55    "background\0"     No_argument       "b"
     56    "broadcast\0"      No_argument       "B"
     57    IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument       "a")
     58    IF_FEATURE_UDHCP_PORT("client-port\0"   Required_argument "P")
     59    ;
    3560#endif
    36 #include <linux/filter.h>
    37 
    38 /* struct client_config_t client_config is in bb_common_bufsiz1 */
     61/* Must match getopt32 option string order */
     62enum {
     63    OPT_C = 1 << 0,
     64    OPT_V = 1 << 1,
     65    OPT_H = 1 << 2,
     66    OPT_h = 1 << 3,
     67    OPT_F = 1 << 4,
     68    OPT_i = 1 << 5,
     69    OPT_n = 1 << 6,
     70    OPT_p = 1 << 7,
     71    OPT_q = 1 << 8,
     72    OPT_R = 1 << 9,
     73    OPT_r = 1 << 10,
     74    OPT_s = 1 << 11,
     75    OPT_T = 1 << 12,
     76    OPT_t = 1 << 13,
     77    OPT_S = 1 << 14,
     78    OPT_A = 1 << 15,
     79    OPT_O = 1 << 16,
     80    OPT_o = 1 << 17,
     81    OPT_x = 1 << 18,
     82    OPT_f = 1 << 19,
     83    OPT_B = 1 << 20,
     84/* The rest has variable bit positions, need to be clever */
     85    OPTBIT_B = 20,
     86    USE_FOR_MMU(             OPTBIT_b,)
     87    IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
     88    IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
     89    USE_FOR_MMU(             OPT_b = 1 << OPTBIT_b,)
     90    IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
     91    IF_FEATURE_UDHCP_PORT(   OPT_P = 1 << OPTBIT_P,)
     92};
    3993
    4094
     
    46100    [OPTION_IP_PAIR         ] = sizeof("255.255.255.255 ") * 2,
    47101    [OPTION_STATIC_ROUTES   ] = sizeof("255.255.255.255/32 255.255.255.255 "),
     102    [OPTION_6RD             ] = sizeof("32 128 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 255.255.255.255 "),
    48103    [OPTION_STRING          ] = 1,
     104    [OPTION_STRING_HOST     ] = 1,
    49105#if ENABLE_FEATURE_UDHCP_RFC3397
    50106    [OPTION_DNS_STRING      ] = 1, /* unused */
     
    81137}
    82138
     139/* Check if a given label represents a valid DNS label
     140 * Return pointer to the first character after the label upon success,
     141 * NULL otherwise.
     142 * See RFC1035, 2.3.1
     143 */
     144/* We don't need to be particularly anal. For example, allowing _, hyphen
     145 * at the end, or leading and trailing dots would be ok, since it
     146 * can't be used for attacks. (Leading hyphen can be, if someone uses
     147 * cmd "$hostname"
     148 * in the script: then hostname may be treated as an option)
     149 */
     150static const char *valid_domain_label(const char *label)
     151{
     152    unsigned char ch;
     153    unsigned pos = 0;
     154
     155    for (;;) {
     156        ch = *label;
     157        if ((ch|0x20) < 'a' || (ch|0x20) > 'z') {
     158            if (pos == 0) {
     159                /* label must begin with letter */
     160                return NULL;
     161            }
     162            if (ch < '0' || ch > '9') {
     163                if (ch == '\0' || ch == '.')
     164                    return label;
     165                /* DNS allows only '-', but we are more permissive */
     166                if (ch != '-' && ch != '_')
     167                    return NULL;
     168            }
     169        }
     170        label++;
     171        pos++;
     172        //Do we want this?
     173        //if (pos > 63) /* NS_MAXLABEL; labels must be 63 chars or less */
     174        //  return NULL;
     175    }
     176}
     177
     178/* Check if a given name represents a valid DNS name */
     179/* See RFC1035, 2.3.1 */
     180static int good_hostname(const char *name)
     181{
     182    //const char *start = name;
     183
     184    for (;;) {
     185        name = valid_domain_label(name);
     186        if (!name)
     187            return 0;
     188        if (!name[0])
     189            return 1;
     190            //Do we want this?
     191            //return ((name - start) < 1025); /* NS_MAXDNAME */
     192        name++;
     193    }
     194}
     195
    83196/* Create "opt_name=opt_value" string */
    84197static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_optflag *optflag, const char *opt_name)
     
    88201    char *dest, *ret;
    89202
    90     /* option points to OPT_DATA, need to go back and get OPT_LEN */
    91     len = option[OPT_LEN - OPT_DATA];
     203    /* option points to OPT_DATA, need to go back to get OPT_LEN */
     204    len = option[-OPT_DATA + OPT_LEN];
    92205
    93206    type = optflag->flags & OPTION_TYPE_MASK;
    94207    optlen = dhcp_option_lengths[type];
    95     upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen);
     208    upper_length = len_of_option_as_string[type]
     209        * ((unsigned)(len + optlen - 1) / (unsigned)optlen);
    96210
    97211    dest = ret = xmalloc(upper_length + strlen(opt_name) + 2);
     
    99213
    100214    while (len >= optlen) {
    101         unsigned ip_ofs = 0;
    102 
    103215        switch (type) {
     216        case OPTION_IP:
    104217        case OPTION_IP_PAIR:
    105218            dest += sprint_nip(dest, "", option);
    106             *dest++ = '/';
    107             ip_ofs = 4;
    108             /* fall through */
    109         case OPTION_IP:
    110             dest += sprint_nip(dest, "", option + ip_ofs);
     219            if (type == OPTION_IP)
     220                break;
     221            dest += sprint_nip(dest, "/", option + 4);
    111222            break;
    112223//      case OPTION_BOOLEAN:
     
    130241            break;
    131242        }
     243        /* Note: options which use 'return' instead of 'break'
     244         * (for example, OPTION_STRING) skip the code which handles
     245         * the case of list of options.
     246         */
    132247        case OPTION_STRING:
     248        case OPTION_STRING_HOST:
    133249            memcpy(dest, option, len);
    134250            dest[len] = '\0';
    135             return ret;  /* Short circuit this case */
     251            if (type == OPTION_STRING_HOST && !good_hostname(dest))
     252                safe_strncpy(dest, "bad", len);
     253            return ret;
    136254        case OPTION_STATIC_ROUTES: {
    137255            /* Option binary format:
     
    178296            return ret;
    179297        }
     298        case OPTION_6RD:
     299            /* Option binary format (see RFC 5969):
     300             *  0                   1                   2                   3
     301             *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     302             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     303             * |  OPTION_6RD   | option-length |  IPv4MaskLen  |  6rdPrefixLen |
     304             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     305             * |                           6rdPrefix                           |
     306             * ...                        (16 octets)                        ...
     307             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     308             * ...                   6rdBRIPv4Address(es)                    ...
     309             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     310             * We convert it to a string
     311             * "IPv4MaskLen 6rdPrefixLen 6rdPrefix 6rdBRIPv4Address..."
     312             *
     313             * Sanity check: ensure that our length is at least 22 bytes, that
     314             * IPv4MaskLen <= 32,
     315             * 6rdPrefixLen <= 128,
     316             * 6rdPrefixLen + (32 - IPv4MaskLen) <= 128
     317             * (2nd condition need no check - it follows from 1st and 3rd).
     318             * Else, return envvar with empty value ("optname=")
     319             */
     320            if (len >= (1 + 1 + 16 + 4)
     321             && option[0] <= 32
     322             && (option[1] + 32 - option[0]) <= 128
     323            ) {
     324                /* IPv4MaskLen */
     325                dest += sprintf(dest, "%u ", *option++);
     326                /* 6rdPrefixLen */
     327                dest += sprintf(dest, "%u ", *option++);
     328                /* 6rdPrefix */
     329                dest += sprint_nip6(dest, /* "", */ option);
     330                option += 16;
     331                len -= 1 + 1 + 16 + 4;
     332                /* "+ 4" above corresponds to the length of IPv4 addr
     333                 * we consume in the loop below */
     334                while (1) {
     335                    /* 6rdBRIPv4Address(es) */
     336                    dest += sprint_nip(dest, " ", option);
     337                    option += 4;
     338                    len -= 4; /* do we have yet another 4+ bytes? */
     339                    if (len < 0)
     340                        break; /* no */
     341                }
     342            }
     343
     344            return ret;
    180345#if ENABLE_FEATURE_UDHCP_RFC3397
    181346        case OPTION_DNS_STRING:
     
    217382#endif
    218383        } /* switch */
     384
     385        /* If we are here, try to format any remaining data
     386         * in the option as another, similarly-formatted option
     387         */
    219388        option += optlen;
    220389        len -= optlen;
     
    222391// Should we bail out/warn if we see multi-ip option which is
    223392// not allowed to be such (for example, DHCP_BROADCAST)? -
    224         if (len <= 0 /* || !(optflag->flags & OPTION_LIST) */)
     393        if (len < optlen /* || !(optflag->flags & OPTION_LIST) */)
    225394            break;
    226395        *dest++ = ' ';
    227396        *dest = '\0';
    228     }
     397    } /* while */
     398
    229399    return ret;
    230400}
     
    239409    uint8_t *temp;
    240410    uint8_t overload = 0;
     411
     412#define BITMAP unsigned
     413#define BBITS (sizeof(BITMAP) * 8)
     414#define BMASK(i) (1 << (i & (sizeof(BITMAP) * 8 - 1)))
     415#define FOUND_OPTS(i) (found_opts[(unsigned)i / BBITS])
     416    BITMAP found_opts[256 / BBITS];
     417
     418    memset(found_opts, 0, sizeof(found_opts));
    241419
    242420    /* We need 6 elements for:
     
    251429    /* +1 element for each option, +2 for subnet option: */
    252430    if (packet) {
    253         for (i = 0; dhcp_optflags[i].code; i++) {
    254             if (udhcp_get_option(packet, dhcp_optflags[i].code)) {
    255                 if (dhcp_optflags[i].code == DHCP_SUBNET)
    256                     envc++; /* for mton */
     431        /* note: do not search for "pad" (0) and "end" (255) options */
     432//TODO: change logic to scan packet _once_
     433        for (i = 1; i < 255; i++) {
     434            temp = udhcp_get_option(packet, i);
     435            if (temp) {
     436                if (i == DHCP_OPTION_OVERLOAD)
     437                    overload = *temp;
     438                else if (i == DHCP_SUBNET)
     439                    envc++; /* for $mask */
    257440                envc++;
     441                /*if (i != DHCP_MESSAGE_TYPE)*/
     442                FOUND_OPTS(i) |= BMASK(i);
    258443            }
    259444        }
    260         temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD);
    261         if (temp)
    262             overload = *temp;
    263     }
    264     curr = envp = xzalloc(sizeof(char *) * envc);
     445    }
     446    curr = envp = xzalloc(sizeof(envp[0]) * envc);
    265447
    266448    *curr = xasprintf("interface=%s", client_config.interface);
     
    270452        return envp;
    271453
     454    /* Export BOOTP fields. Fields we don't (yet?) export:
     455     * uint8_t op;      // always BOOTREPLY
     456     * uint8_t htype;   // hardware address type. 1 = 10mb ethernet
     457     * uint8_t hlen;    // hardware address length
     458     * uint8_t hops;    // used by relay agents only
     459     * uint32_t xid;
     460     * uint16_t secs;   // elapsed since client began acquisition/renewal
     461     * uint16_t flags;  // only one flag so far: bcast. Never set by server
     462     * uint32_t ciaddr; // client IP (usually == yiaddr. can it be different
     463     *                  // if during renew server wants to give us differn IP?)
     464     * uint32_t gateway_nip; // relay agent IP address
     465     * uint8_t chaddr[16]; // link-layer client hardware address (MAC)
     466     * TODO: export gateway_nip as $giaddr?
     467     */
     468    /* Most important one: yiaddr as $ip */
    272469    *curr = xmalloc(sizeof("ip=255.255.255.255"));
    273470    sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr);
    274471    putenv(*curr++);
    275 
    276     opt_name = dhcp_option_strings;
    277     i = 0;
    278     while (*opt_name) {
    279         temp = udhcp_get_option(packet, dhcp_optflags[i].code);
    280         if (!temp)
    281             goto next;
    282         *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name);
    283         putenv(*curr++);
    284         if (dhcp_optflags[i].code == DHCP_SUBNET) {
    285             /* Subnet option: make things like "$ip/$mask" possible */
    286             uint32_t subnet;
    287             move_from_unaligned32(subnet, temp);
    288             *curr = xasprintf("mask=%d", mton(subnet));
    289             putenv(*curr++);
    290         }
    291  next:
    292         opt_name += strlen(opt_name) + 1;
    293         i++;
    294     }
    295472    if (packet->siaddr_nip) {
     473        /* IP address of next server to use in bootstrap */
    296474        *curr = xmalloc(sizeof("siaddr=255.255.255.255"));
    297475        sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip);
     
    308486        putenv(*curr++);
    309487    }
     488
     489    /* Export known DHCP options */
     490    opt_name = dhcp_option_strings;
     491    i = 0;
     492    while (*opt_name) {
     493        uint8_t code = dhcp_optflags[i].code;
     494        BITMAP *found_ptr = &FOUND_OPTS(code);
     495        BITMAP found_mask = BMASK(code);
     496        if (!(*found_ptr & found_mask))
     497            goto next;
     498        *found_ptr &= ~found_mask; /* leave only unknown options */
     499        temp = udhcp_get_option(packet, code);
     500        *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name);
     501        putenv(*curr++);
     502        if (code == DHCP_SUBNET) {
     503            /* Subnet option: make things like "$ip/$mask" possible */
     504            uint32_t subnet;
     505            move_from_unaligned32(subnet, temp);
     506            *curr = xasprintf("mask=%u", mton(subnet));
     507            putenv(*curr++);
     508        }
     509 next:
     510        opt_name += strlen(opt_name) + 1;
     511        i++;
     512    }
     513    /* Export unknown options */
     514    for (i = 0; i < 256;) {
     515        BITMAP bitmap = FOUND_OPTS(i);
     516        if (!bitmap) {
     517            i += BBITS;
     518            continue;
     519        }
     520        if (bitmap & BMASK(i)) {
     521            unsigned len, ofs;
     522
     523            temp = udhcp_get_option(packet, i);
     524            /* udhcp_get_option returns ptr to data portion,
     525             * need to go back to get len
     526             */
     527            len = temp[-OPT_DATA + OPT_LEN];
     528            *curr = xmalloc(sizeof("optNNN=") + 1 + len*2);
     529            ofs = sprintf(*curr, "opt%u=", i);
     530            *bin2hex(*curr + ofs, (void*) temp, len) = '\0';
     531            putenv(*curr++);
     532        }
     533        i++;
     534    }
     535
    310536    return envp;
    311537}
     
    316542    char **envp, **curr;
    317543    char *argv[3];
    318 
    319     if (client_config.script == NULL)
    320         return;
    321544
    322545    envp = fill_envp(packet);
     
    347570static void init_packet(struct dhcp_packet *packet, char type)
    348571{
     572    uint16_t secs;
     573
    349574    /* Fill in: op, htype, hlen, cookie fields; message type option: */
    350575    udhcp_init_header(packet, type);
    351576
    352577    packet->xid = random_xid();
     578
     579    client_config.last_secs = monotonic_sec();
     580    if (client_config.first_secs == 0)
     581        client_config.first_secs = client_config.last_secs;
     582    secs = client_config.last_secs - client_config.first_secs;
     583    packet->secs = htons(secs);
    353584
    354585    memcpy(packet->chaddr, client_config.client_mac, 6);
     
    359590static void add_client_options(struct dhcp_packet *packet)
    360591{
    361     uint8_t c;
    362592    int i, end, len;
    363593
     
    369599    end = udhcp_end_option(packet->options);
    370600    len = 0;
    371     for (i = 0; (c = dhcp_optflags[i].code) != 0; i++) {
    372         if ((   (dhcp_optflags[i].flags & OPTION_REQ)
    373              && !client_config.no_default_options
    374             )
    375          || (client_config.opt_mask[c >> 3] & (1 << (c & 7)))
    376         ) {
    377             packet->options[end + OPT_DATA + len] = c;
     601    for (i = 1; i < DHCP_END; i++) {
     602        if (client_config.opt_mask[i >> 3] & (1 << (i & 7))) {
     603            packet->options[end + OPT_DATA + len] = i;
    378604            len++;
    379605        }
     
    392618        udhcp_add_binary_option(packet, client_config.fqdn);
    393619
     620    /* Request broadcast replies if we have no IP addr */
     621    if ((option_mask32 & OPT_B) && packet->ciaddr == 0)
     622        packet->flags |= htons(BROADCAST_FLAG);
     623
    394624    /* Add -x options if any */
    395625    {
     
    404634//          strncpy((char*)packet->file, client_config.boot_file, sizeof(packet->file) - 1);
    405635    }
     636
     637    // This will be needed if we remove -V VENDOR_STR in favor of
     638    // -x vendor:VENDOR_STR
     639    //if (!udhcp_find_option(packet.options, DHCP_VENDOR))
     640    //  /* not set, set the default vendor ID */
     641    //  ...add (DHCP_VENDOR, "udhcp "BB_VER) opt...
    406642}
    407643
     
    548784/* Broadcast a DHCP decline message */
    549785/* NOINLINE: limit stack usage in caller */
    550 static NOINLINE int send_decline(uint32_t xid, uint32_t server, uint32_t requested)
     786static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t requested)
    551787{
    552788    struct dhcp_packet packet;
     
    557793    init_packet(&packet, DHCPDECLINE);
    558794
     795#if 0
    559796    /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client,
    560797     * but in case the server is buggy and wants DHCPDECLINE's xid
     
    563800     */
    564801    packet.xid = xid;
     802#endif
    565803    /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */
    566804    udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
     
    599837    struct ip_udp_dhcp_packet packet;
    600838    uint16_t check;
    601 
    602     memset(&packet, 0, sizeof(packet));
    603     bytes = safe_read(fd, &packet, sizeof(packet));
    604     if (bytes < 0) {
    605         log1("Packet read error, ignoring");
    606         /* NB: possible down interface, etc. Caller should pause. */
    607         return bytes; /* returns -1 */
     839    unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
     840    struct iovec iov;
     841    struct msghdr msg;
     842    struct cmsghdr *cmsg;
     843
     844    /* used to use just safe_read(fd, &packet, sizeof(packet))
     845     * but we need to check for TP_STATUS_CSUMNOTREADY :(
     846     */
     847    iov.iov_base = &packet;
     848    iov.iov_len = sizeof(packet);
     849    memset(&msg, 0, sizeof(msg));
     850    msg.msg_iov = &iov;
     851    msg.msg_iovlen = 1;
     852    msg.msg_control = cmsgbuf;
     853    msg.msg_controllen = sizeof(cmsgbuf);
     854    for (;;) {
     855        bytes = recvmsg(fd, &msg, 0);
     856        if (bytes < 0) {
     857            if (errno == EINTR)
     858                continue;
     859            log1("Packet read error, ignoring");
     860            /* NB: possible down interface, etc. Caller should pause. */
     861            return bytes; /* returns -1 */
     862        }
     863        break;
    608864    }
    609865
     
    623879
    624880    /* make sure its the right packet for us, and that it passes sanity checks */
    625     if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION
     881    if (packet.ip.protocol != IPPROTO_UDP
     882     || packet.ip.version != IPVERSION
    626883     || packet.ip.ihl != (sizeof(packet.ip) >> 2)
    627884     || packet.udp.dest != htons(CLIENT_PORT)
     
    636893    check = packet.ip.check;
    637894    packet.ip.check = 0;
    638     if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) {
     895    if (check != inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip))) {
    639896        log1("Bad IP header checksum, ignoring");
    640897        return -2;
     898    }
     899
     900    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
     901        if (cmsg->cmsg_level == SOL_PACKET
     902         && cmsg->cmsg_type == PACKET_AUXDATA
     903        ) {
     904            /* some VMs don't checksum UDP and TCP data
     905             * they send to the same physical machine,
     906             * here we detect this case:
     907             */
     908            struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg);
     909            if (aux->tp_status & TP_STATUS_CSUMNOTREADY)
     910                goto skip_udp_sum_check;
     911        }
    641912    }
    642913
     
    647918    check = packet.udp.check;
    648919    packet.udp.check = 0;
    649     if (check && check != udhcp_checksum(&packet, bytes)) {
     920    if (check && check != inet_cksum((uint16_t *)&packet, bytes)) {
    650921        log1("Packet with bad UDP checksum received, ignoring");
    651922        return -2;
    652923    }
    653 
    654     memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp)));
    655 
    656     if (dhcp_pkt->cookie != htonl(DHCP_MAGIC)) {
     924 skip_udp_sum_check:
     925
     926    if (packet.data.cookie != htonl(DHCP_MAGIC)) {
    657927        bb_info_msg("Packet with bad magic, ignoring");
    658928        return -2;
    659929    }
    660     log1("Got valid DHCP packet");
    661     udhcp_dump_packet(dhcp_pkt);
    662     return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
     930
     931    log1("Received a packet");
     932    udhcp_dump_packet(&packet.data);
     933
     934    bytes -= sizeof(packet.ip) + sizeof(packet.udp);
     935    memcpy(dhcp_pkt, &packet.data, bytes);
     936    return bytes;
    663937}
    664938
     
    715989     * TODO: make conditional?
    716990     */
    717 #define SERVER_AND_CLIENT_PORTS  ((67 << 16) + 68)
    718991    static const struct sock_filter filter_instr[] = {
    719         /* check for udp */
     992        /* load 9th byte (protocol) */
    720993        BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
    721         BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0),     /* L5, L1, is UDP? */
    722         /* ugly check for arp on ethernet-like and IPv4 */
    723         BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),                      /* L1: */
    724         BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4),      /* L3, L4 */
    725         /* skip IP header */
    726         BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),                     /* L5: */
    727         /* check udp source and destination ports */
    728         BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0),
    729         BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1), /* L3, L4 */
    730         /* returns */
    731         BPF_STMT(BPF_RET|BPF_K, 0x0fffffff ),                   /* L3: pass */
    732         BPF_STMT(BPF_RET|BPF_K, 0),                             /* L4: reject */
     994        /* jump to L1 if it is IPPROTO_UDP, else to L4 */
     995        BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
     996        /* L1: load halfword from offset 6 (flags and frag offset) */
     997        BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
     998        /* jump to L4 if any bits in frag offset field are set, else to L2 */
     999        BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
     1000        /* L2: skip IP header (load index reg with header len) */
     1001        BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),
     1002        /* load udp destination port from halfword[header_len + 2] */
     1003        BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
     1004        /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */
     1005        BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
     1006        /* L3: accept packet */
     1007        BPF_STMT(BPF_RET|BPF_K, 0xffffffff),
     1008        /* L4: discard packet */
     1009        BPF_STMT(BPF_RET|BPF_K, 0),
    7331010    };
    7341011    static const struct sock_fprog filter_prog = {
     
    7411018
    7421019    fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
    743     log1("Got raw socket fd %d", fd); //log2?
    744 
    745     if (SERVER_PORT == 67 && CLIENT_PORT == 68) {
    746         /* Use only if standard ports are in use */
    747         /* Ignoring error (kernel may lack support for this) */
    748         if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
    749                 sizeof(filter_prog)) >= 0)
    750             log1("Attached filter to raw socket fd %d", fd); // log?
    751     }
     1020    log1("Got raw socket fd"); //log2?
    7521021
    7531022    sock.sll_family = AF_PACKET;
     
    7551024    sock.sll_ifindex = ifindex;
    7561025    xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
     1026
     1027    if (CLIENT_PORT == 68) {
     1028        /* Use only if standard port is in use */
     1029        /* Ignoring error (kernel may lack support for this) */
     1030        if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
     1031                sizeof(filter_prog)) >= 0)
     1032            log1("Attached filter to raw socket fd"); // log?
     1033    }
     1034
     1035    if (setsockopt(fd, SOL_PACKET, PACKET_AUXDATA,
     1036            &const_int_1, sizeof(int)) < 0
     1037    ) {
     1038        if (errno != ENOPROTOOPT)
     1039            log1("Can't set PACKET_AUXDATA on raw socket");
     1040    }
     1041
    7571042    log1("Created raw socket");
    7581043
     
    7801065}
    7811066
     1067/* Called only on SIGUSR1 */
    7821068static void perform_renew(void)
    7831069{
     
    8021088}
    8031089
    804 static void perform_release(uint32_t requested_ip, uint32_t server_addr)
     1090static void perform_release(uint32_t server_addr, uint32_t requested_ip)
    8051091{
    8061092    char buffer[sizeof("255.255.255.255")];
     
    8501136//usage:#endif
    8511137//usage:#define udhcpc_trivial_usage
    852 //usage:       "[-fbnq"IF_UDHCP_VERBOSE("v")"oCR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n"
    853 //usage:       "    [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
     1138//usage:       "[-fbnq"IF_UDHCP_VERBOSE("v")"oCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n"
     1139//usage:       "    [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
    8541140//usage:#define udhcpc_full_usage "\n"
    8551141//usage:    IF_LONG_OPTS(
     
    8571143//usage:     "\n    -p,--pidfile FILE   Create pidfile"
    8581144//usage:     "\n    -s,--script PROG    Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
     1145//usage:     "\n    -B,--broadcast      Request broadcast replies"
    8591146//usage:     "\n    -t,--retries N      Send up to N discover packets"
    8601147//usage:     "\n    -T,--timeout N      Pause between packets (default 3 seconds)"
     
    8831170//usage:     "\n                -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
    8841171//usage:     "\n    -F,--fqdn NAME      Ask server to update DNS mapping for NAME"
    885 //usage:     "\n    -H,-h,--hostname NAME   Send NAME as client hostname (default none)"
    8861172//usage:     "\n    -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')"
    8871173//usage:     "\n    -C,--clientid-none  Don't send MAC as client identifier"
     
    8941180//usage:     "\n    -p FILE     Create pidfile"
    8951181//usage:     "\n    -s PROG     Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
     1182//usage:     "\n    -B      Request broadcast replies"
    8961183//usage:     "\n    -t N        Send up to N discover packets"
    8971184//usage:     "\n    -T N        Pause between packets (default 3 seconds)"
     
    9201207//usage:     "\n            -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
    9211208//usage:     "\n    -F NAME     Ask server to update DNS mapping for NAME"
    922 //usage:     "\n    -H,-h NAME  Send NAME as client hostname (default none)"
    9231209//usage:     "\n    -V VENDOR   Vendor identifier (default 'udhcp VERSION')"
    9241210//usage:     "\n    -C      Don't send MAC as client identifier"
     
    9271213//usage:    )
    9281214//usage:    )
     1215//usage:     "\nSignals:"
     1216//usage:     "\n    USR1    Renew lease"
     1217//usage:     "\n    USR2    Release lease"
     1218
    9291219
    9301220int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     
    9421232    uint32_t server_addr = server_addr; /* for compiler */
    9431233    uint32_t requested_ip = 0;
    944     uint32_t xid = 0;
    945     uint32_t lease_seconds = 0; /* can be given as 32-bit quantity */
     1234    uint32_t xid = xid; /* for compiler */
    9461235    int packet_num;
    9471236    int timeout; /* must be signed */
     
    9501239    int max_fd;
    9511240    int retval;
    952     struct timeval tv;
    953     struct dhcp_packet packet;
    9541241    fd_set rfds;
    955 
    956 #if ENABLE_LONG_OPTS
    957     static const char udhcpc_longopts[] ALIGN1 =
    958         "clientid-none\0"  No_argument       "C"
    959         "vendorclass\0"    Required_argument "V"
    960         "hostname\0"       Required_argument "H"
    961         "fqdn\0"           Required_argument "F"
    962         "interface\0"      Required_argument "i"
    963         "now\0"            No_argument       "n"
    964         "pidfile\0"        Required_argument "p"
    965         "quit\0"           No_argument       "q"
    966         "release\0"        No_argument       "R"
    967         "request\0"        Required_argument "r"
    968         "script\0"         Required_argument "s"
    969         "timeout\0"        Required_argument "T"
    970         "version\0"        No_argument       "v"
    971         "retries\0"        Required_argument "t"
    972         "tryagain\0"       Required_argument "A"
    973         "syslog\0"         No_argument       "S"
    974         "request-option\0" Required_argument "O"
    975         "no-default-options\0" No_argument   "o"
    976         "foreground\0"     No_argument       "f"
    977         "background\0"     No_argument       "b"
    978         IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument       "a")
    979         IF_FEATURE_UDHCP_PORT("client-port\0"   Required_argument "P")
    980         ;
    981 #endif
    982     enum {
    983         OPT_C = 1 << 0,
    984         OPT_V = 1 << 1,
    985         OPT_H = 1 << 2,
    986         OPT_h = 1 << 3,
    987         OPT_F = 1 << 4,
    988         OPT_i = 1 << 5,
    989         OPT_n = 1 << 6,
    990         OPT_p = 1 << 7,
    991         OPT_q = 1 << 8,
    992         OPT_R = 1 << 9,
    993         OPT_r = 1 << 10,
    994         OPT_s = 1 << 11,
    995         OPT_T = 1 << 12,
    996         OPT_t = 1 << 13,
    997         OPT_S = 1 << 14,
    998         OPT_A = 1 << 15,
    999         OPT_O = 1 << 16,
    1000         OPT_o = 1 << 17,
    1001         OPT_x = 1 << 18,
    1002         OPT_f = 1 << 19,
    1003 /* The rest has variable bit positions, need to be clever */
    1004         OPTBIT_f = 19,
    1005         USE_FOR_MMU(             OPTBIT_b,)
    1006         IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
    1007         IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
    1008         USE_FOR_MMU(             OPT_b = 1 << OPTBIT_b,)
    1009         IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
    1010         IF_FEATURE_UDHCP_PORT(   OPT_P = 1 << OPTBIT_P,)
    1011     };
    10121242
    10131243    /* Default options */
     
    10201250    /* Parse command line */
    10211251    /* O,x: list; -T,-t,-A take numeric param */
    1022     opt_complementary = "O::x::T+:t+:A+"
    1023 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
    1024         ":vv"
    1025 #endif
    1026         ;
     1252    opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ;
    10271253    IF_LONG_OPTS(applet_long_options = udhcpc_longopts;)
    1028     opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:f"
     1254    opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB"
    10291255        USE_FOR_MMU("b")
    10301256        IF_FEATURE_UDHCPC_ARPING("a")
     
    10381264        , &list_x
    10391265        IF_FEATURE_UDHCP_PORT(, &str_P)
    1040 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
    1041         , &dhcp_verbose
    1042 #endif
    1043         );
    1044     if (opt & (OPT_h|OPT_H))
     1266        IF_UDHCP_VERBOSE(, &dhcp_verbose)
     1267    );
     1268    if (opt & (OPT_h|OPT_H)) {
     1269        //msg added 2011-11
     1270        bb_error_msg("option -h NAME is deprecated, use -x hostname:NAME");
    10451271        client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
     1272    }
    10461273    if (opt & OPT_F) {
    10471274        /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */
     
    10671294    }
    10681295#endif
    1069     if (opt & OPT_o)
    1070         client_config.no_default_options = 1;
    10711296    while (list_O) {
    10721297        char *optstr = llist_pop(&list_O);
    1073         unsigned n = udhcp_option_idx(optstr);
    1074         n = dhcp_optflags[n].code;
     1298        unsigned n = bb_strtou(optstr, NULL, 0);
     1299        if (errno || n > 254) {
     1300            n = udhcp_option_idx(optstr);
     1301            n = dhcp_optflags[n].code;
     1302        }
    10751303        client_config.opt_mask[n >> 3] |= 1 << (n & 7);
     1304    }
     1305    if (!(opt & OPT_o)) {
     1306        unsigned i, n;
     1307        for (i = 0; (n = dhcp_optflags[i].code) != 0; i++) {
     1308            if (dhcp_optflags[i].flags & OPTION_REQ) {
     1309                client_config.opt_mask[n >> 3] |= 1 << (n & 7);
     1310            }
     1311        }
    10761312    }
    10771313    while (list_x) {
     
    11011337        memcpy(clientid_mac_ptr, client_config.client_mac, 6);
    11021338    }
    1103     if (str_V[0] != '\0')
     1339    if (str_V[0] != '\0') {
     1340        // can drop -V, str_V, client_config.vendorclass,
     1341        // but need to add "vendor" to the list of recognized
     1342        // string opts for this to work;
     1343        // and need to tweak add_client_options() too...
     1344        // ...so the question is, should we?
     1345        //bb_error_msg("option -V VENDOR is deprecated, use -x vendor:VENDOR");
    11041346        client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
     1347    }
     1348
    11051349#if !BB_MMU
    11061350    /* on NOMMU reexec (i.e., background) early */
     
    11401384     */
    11411385    for (;;) {
     1386        struct timeval tv;
     1387        struct dhcp_packet packet;
    11421388        /* silence "uninitialized!" warning */
    11431389        unsigned timestamp_before_wait = timestamp_before_wait;
     
    11591405        /* If we already timed out, fall through with retval = 0, else... */
    11601406        if ((int)tv.tv_sec > 0) {
     1407            log1("Waiting on select %u seconds", (int)tv.tv_sec);
    11611408            timestamp_before_wait = (unsigned)monotonic_sec();
    1162             log1("Waiting on select...");
    11631409            retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
    11641410            if (retval < 0) {
     
    11871433                    client_config.client_mac)
    11881434            ) {
    1189                 return 1; /* iface is gone? */
     1435                goto ret0; /* iface is gone? */
    11901436            }
    11911437            if (clientid_mac_ptr)
     
    11971443            switch (state) {
    11981444            case INIT_SELECTING:
    1199                 if (packet_num < discover_retries) {
     1445                if (!discover_retries || packet_num < discover_retries) {
    12001446                    if (packet_num == 0)
    12011447                        xid = random_xid();
     
    12261472                continue;
    12271473            case REQUESTING:
    1228                 if (packet_num < discover_retries) {
     1474                if (!discover_retries || packet_num < discover_retries) {
    12291475                    /* send broadcast select packet */
    12301476                    send_select(xid, server_addr, requested_ip);
     
    12431489                /* 1/2 lease passed, enter renewing state */
    12441490                state = RENEWING;
     1491                client_config.first_secs = 0; /* make secs field count from 0 */
    12451492                change_listen_mode(LISTEN_KERNEL);
    12461493                log1("Entering renew state");
     
    12821529                udhcp_run_script(NULL, "deconfig");
    12831530                state = INIT_SELECTING;
     1531                client_config.first_secs = 0; /* make secs field count from 0 */
    12841532                /*timeout = 0; - already is */
    12851533                packet_num = 0;
     
    12981546        switch (udhcp_sp_read(&rfds)) {
    12991547        case SIGUSR1:
     1548            client_config.first_secs = 0; /* make secs field count from 0 */
     1549            already_waited_sec = 0;
    13001550            perform_renew();
    1301             if (state == RENEW_REQUESTED)
     1551            if (state == RENEW_REQUESTED) {
     1552                /* We might be either on the same network
     1553                 * (in which case renew might work),
     1554                 * or we might be on a completely different one
     1555                 * (in which case renew won't ever succeed).
     1556                 * For the second case, must make sure timeout
     1557                 * is not too big, or else we can send
     1558                 * futile renew requests for hours.
     1559                 * (Ab)use -A TIMEOUT value (usually 20 sec)
     1560                 * as a cap on the timeout.
     1561                 */
     1562                if (timeout > tryagain_timeout)
     1563                    timeout = tryagain_timeout;
    13021564                goto case_RENEW_REQUESTED;
     1565            }
    13031566            /* Start things over */
    13041567            packet_num = 0;
     
    13071570            continue;
    13081571        case SIGUSR2:
    1309             perform_release(requested_ip, server_addr);
     1572            perform_release(server_addr, requested_ip);
    13101573            timeout = INT_MAX;
    13111574            continue;
    13121575        case SIGTERM:
    13131576            bb_info_msg("Received SIGTERM");
    1314             if (opt & OPT_R) /* release on quit */
    1315                 perform_release(requested_ip, server_addr);
    13161577            goto ret0;
    13171578        }
     
    13661627        switch (state) {
    13671628        case INIT_SELECTING:
    1368             /* Must be a DHCPOFFER to one of our xid's */
     1629            /* Must be a DHCPOFFER */
    13691630            if (*message == DHCPOFFER) {
    1370         /* TODO: why we don't just fetch server's IP from IP header? */
     1631/* What exactly is server's IP? There are several values.
     1632 * Example DHCP offer captured with tchdump:
     1633 *
     1634 * 10.34.25.254:67 > 10.34.25.202:68 // IP header's src
     1635 * BOOTP fields:
     1636 * Your-IP 10.34.25.202
     1637 * Server-IP 10.34.32.125   // "next server" IP
     1638 * Gateway-IP 10.34.25.254  // relay's address (if DHCP relays are in use)
     1639 * DHCP options:
     1640 * DHCP-Message Option 53, length 1: Offer
     1641 * Server-ID Option 54, length 4: 10.34.255.7       // "server ID"
     1642 * Default-Gateway Option 3, length 4: 10.34.25.254 // router
     1643 *
     1644 * We think that real server IP (one to use in renew/release)
     1645 * is one in Server-ID option. But I am not 100% sure.
     1646 * IP header's src and Gateway-IP (same in this example)
     1647 * might work too.
     1648 * "Next server" and router are definitely wrong ones to use, though...
     1649 */
    13711650                temp = udhcp_get_option(&packet, DHCP_SERVER_ID);
    13721651                if (!temp) {
     
    13921671        case REBINDING:
    13931672            if (*message == DHCPACK) {
     1673                uint32_t lease_seconds;
     1674                struct in_addr temp_addr;
     1675
    13941676                temp = udhcp_get_option(&packet, DHCP_LEASE_TIME);
    13951677                if (!temp) {
     
    14001682                    move_from_unaligned32(lease_seconds, temp);
    14011683                    lease_seconds = ntohl(lease_seconds);
    1402                     lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */
    1403                     if (lease_seconds < 10) /* and not too small */
    1404                         lease_seconds = 10;
     1684                    /* paranoia: must not be too small and not prone to overflows */
     1685                    if (lease_seconds < 0x10)
     1686                        lease_seconds = 0x10;
     1687                    if (lease_seconds >= 0x10000000)
     1688                        lease_seconds = 0x0fffffff;
    14051689                }
    14061690#if ENABLE_FEATURE_UDHCPC_ARPING
     
    14231707                        bb_info_msg("Offered address is in use "
    14241708                            "(got ARP reply), declining");
    1425                         send_decline(xid, server_addr, packet.yiaddr);
     1709                        send_decline(/*xid,*/ server_addr, packet.yiaddr);
    14261710
    14271711                        if (state != REQUESTING)
     
    14291713                        change_listen_mode(LISTEN_RAW);
    14301714                        state = INIT_SELECTING;
     1715                        client_config.first_secs = 0; /* make secs field count from 0 */
    14311716                        requested_ip = 0;
    14321717                        timeout = tryagain_timeout;
     
    14391724                /* enter bound state */
    14401725                timeout = lease_seconds / 2;
    1441                 {
    1442                     struct in_addr temp_addr;
    1443                     temp_addr.s_addr = packet.yiaddr;
    1444                     bb_info_msg("Lease of %s obtained, lease time %u",
    1445                         inet_ntoa(temp_addr), (unsigned)lease_seconds);
    1446                 }
     1726                temp_addr.s_addr = packet.yiaddr;
     1727                bb_info_msg("Lease of %s obtained, lease time %u",
     1728                    inet_ntoa(temp_addr), (unsigned)lease_seconds);
    14471729                requested_ip = packet.yiaddr;
    14481730                udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew");
     
    14511733                change_listen_mode(LISTEN_NONE);
    14521734                if (opt & OPT_q) { /* quit after lease */
    1453                     if (opt & OPT_R) /* release on quit */
    1454                         perform_release(requested_ip, server_addr);
    14551735                    goto ret0;
    14561736                }
     
    14641744                }
    14651745#endif
     1746                /* make future renew packets use different xid */
     1747                /* xid = random_xid(); ...but why bother? */
    14661748                already_waited_sec = 0;
    14671749                continue; /* back to main loop */
     
    14761758                sleep(3); /* avoid excessive network traffic */
    14771759                state = INIT_SELECTING;
     1760                client_config.first_secs = 0; /* make secs field count from 0 */
    14781761                requested_ip = 0;
    14791762                timeout = 0;
     
    14891772
    14901773 ret0:
     1774    if (opt & OPT_R) /* release on quit */
     1775        perform_release(server_addr, requested_ip);
    14911776    retval = 0;
    14921777 ret:
Note: See TracChangeset for help on using the changeset viewer.