~ubuntu-branches/ubuntu/utopic/busybox/utopic

« back to all changes in this revision

Viewing changes to networking/udhcp/dhcpc.c

  • Committer: Package Import Robot
  • Author(s): Steve Langasek
  • Date: 2012-05-01 03:35:20 UTC
  • mfrom: (2.1.29 sid)
  • Revision ID: package-import@ubuntu.com-20120501033520-3nb8wjf4bp524txp
Tags: 1:1.19.3-7ubuntu1
* Merge from Debian unstable, remaining changes:
  - [udeb] Enable chvt, killall, losetup, NFS mount, od, ping, ping6, and
    stat.
  - [deb, static] Enable CGI support for httpd.
  - Enable 'mount -f' and mount helpers for all targets.
  - Add busybox-initramfs.
  - test-bin.patch: Move test and friends to /bin.
  - static-sh-alias.patch: Add static-sh alias name for ash, and install
    /bin/static-sh symlink to busybox in busybox-static.
  - debian/patches/fix-64-bit-permissions.patch: mkdir: fix permissions
    on 64-bit platforms.  Taken from upstream.
  - Filter out -Werror=format-security from CFLAGS passed by
    dpkg-buildpackage, at least for now.
* Dropped changes, included in Debian:
  - [deb] Enable mdev.
  - Add cross-compiling support.
* Disable NFS mount in the static build; needs a newer upstream version of
  busybox for compatibility with glibc 2.15.
* Set V=1 in debian/rules, to get more meaningful build logs.
* Export the dpkg-buildflags to the environment, so we pick up hardening
  now that dpkg doesn't export them for us.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
#include "dhcpd.h"
26
26
#include "dhcpc.h"
27
27
 
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>
35
 
#endif
 
28
#include <netinet/if_ether.h>
 
29
#include <netpacket/packet.h>
36
30
#include <linux/filter.h>
37
31
 
38
32
/* struct client_config_t client_config is in bb_common_bufsiz1 */
39
33
 
40
34
 
 
35
#if ENABLE_LONG_OPTS
 
36
static 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
        "version\0"        No_argument       "v"
 
50
        "retries\0"        Required_argument "t"
 
51
        "tryagain\0"       Required_argument "A"
 
52
        "syslog\0"         No_argument       "S"
 
53
        "request-option\0" Required_argument "O"
 
54
        "no-default-options\0" No_argument   "o"
 
55
        "foreground\0"     No_argument       "f"
 
56
        "background\0"     No_argument       "b"
 
57
        "broadcast\0"      No_argument       "B"
 
58
        IF_FEATURE_UDHCPC_ARPING("arping\0"     No_argument       "a")
 
59
        IF_FEATURE_UDHCP_PORT("client-port\0"   Required_argument "P")
 
60
        ;
 
61
#endif
 
62
/* Must match getopt32 option string order */
 
63
enum {
 
64
        OPT_C = 1 << 0,
 
65
        OPT_V = 1 << 1,
 
66
        OPT_H = 1 << 2,
 
67
        OPT_h = 1 << 3,
 
68
        OPT_F = 1 << 4,
 
69
        OPT_i = 1 << 5,
 
70
        OPT_n = 1 << 6,
 
71
        OPT_p = 1 << 7,
 
72
        OPT_q = 1 << 8,
 
73
        OPT_R = 1 << 9,
 
74
        OPT_r = 1 << 10,
 
75
        OPT_s = 1 << 11,
 
76
        OPT_T = 1 << 12,
 
77
        OPT_t = 1 << 13,
 
78
        OPT_S = 1 << 14,
 
79
        OPT_A = 1 << 15,
 
80
        OPT_O = 1 << 16,
 
81
        OPT_o = 1 << 17,
 
82
        OPT_x = 1 << 18,
 
83
        OPT_f = 1 << 19,
 
84
        OPT_B = 1 << 20,
 
85
/* The rest has variable bit positions, need to be clever */
 
86
        OPTBIT_B = 20,
 
87
        USE_FOR_MMU(             OPTBIT_b,)
 
88
        IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
 
89
        IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
 
90
        USE_FOR_MMU(             OPT_b = 1 << OPTBIT_b,)
 
91
        IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
 
92
        IF_FEATURE_UDHCP_PORT(   OPT_P = 1 << OPTBIT_P,)
 
93
};
 
94
 
 
95
 
41
96
/*** Script execution code ***/
42
97
 
43
98
/* get a rough idea of how long an option will be (rounding up...) */
239
294
        uint8_t *temp;
240
295
        uint8_t overload = 0;
241
296
 
 
297
#define BITMAP unsigned
 
298
#define BBITS (sizeof(BITMAP) * 8)
 
299
#define BMASK(i) (1 << (i & (sizeof(BITMAP) * 8 - 1)))
 
300
#define FOUND_OPTS(i) (found_opts[(unsigned)i / BBITS])
 
301
        BITMAP found_opts[256 / BBITS];
 
302
 
 
303
        memset(found_opts, 0, sizeof(found_opts));
 
304
 
242
305
        /* We need 6 elements for:
243
306
         * "interface=IFACE"
244
307
         * "ip=N.N.N.N" from packet->yiaddr
250
313
        envc = 6;
251
314
        /* +1 element for each option, +2 for subnet option: */
252
315
        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)
 
316
                /* note: do not search for "pad" (0) and "end" (255) options */
 
317
                for (i = 1; i < 255; i++) {
 
318
                        temp = udhcp_get_option(packet, i);
 
319
                        if (temp) {
 
320
                                if (i == DHCP_OPTION_OVERLOAD)
 
321
                                        overload = *temp;
 
322
                                else if (i == DHCP_SUBNET)
256
323
                                        envc++; /* for mton */
257
324
                                envc++;
 
325
                                /*if (i != DHCP_MESSAGE_TYPE)*/
 
326
                                FOUND_OPTS(i) |= BMASK(i);
258
327
                        }
259
328
                }
260
 
                temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD);
261
 
                if (temp)
262
 
                        overload = *temp;
263
329
        }
264
 
        curr = envp = xzalloc(sizeof(char *) * envc);
 
330
        curr = envp = xzalloc(sizeof(envp[0]) * envc);
265
331
 
266
332
        *curr = xasprintf("interface=%s", client_config.interface);
267
333
        putenv(*curr++);
276
342
        opt_name = dhcp_option_strings;
277
343
        i = 0;
278
344
        while (*opt_name) {
279
 
                temp = udhcp_get_option(packet, dhcp_optflags[i].code);
280
 
                if (!temp)
 
345
                uint8_t code = dhcp_optflags[i].code;
 
346
                BITMAP *found_ptr = &FOUND_OPTS(code);
 
347
                BITMAP found_mask = BMASK(code);
 
348
                if (!(*found_ptr & found_mask))
281
349
                        goto next;
 
350
                *found_ptr &= ~found_mask; /* leave only unknown options */
 
351
                temp = udhcp_get_option(packet, code);
282
352
                *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name);
283
353
                putenv(*curr++);
284
 
                if (dhcp_optflags[i].code == DHCP_SUBNET) {
 
354
                if (code == DHCP_SUBNET) {
285
355
                        /* Subnet option: make things like "$ip/$mask" possible */
286
356
                        uint32_t subnet;
287
357
                        move_from_unaligned32(subnet, temp);
307
377
                *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname);
308
378
                putenv(*curr++);
309
379
        }
 
380
        /* Handle unknown options */
 
381
        for (i = 0; i < 256;) {
 
382
                BITMAP bitmap = FOUND_OPTS(i);
 
383
                if (!bitmap) {
 
384
                        i += BBITS;
 
385
                        continue;
 
386
                }
 
387
                if (bitmap & BMASK(i)) {
 
388
                        unsigned len, ofs;
 
389
 
 
390
                        temp = udhcp_get_option(packet, i);
 
391
                        /* udhcp_get_option returns ptr to data portion,
 
392
                         * need to go back to get len
 
393
                         */
 
394
                        len = temp[-OPT_DATA + OPT_LEN];
 
395
                        *curr = xmalloc(sizeof("optNNN=") + 1 + len*2);
 
396
                        ofs = sprintf(*curr, "opt%u=", i);
 
397
                        bin2hex(*curr + ofs, (void*) temp, len)[0] = '\0';
 
398
                        putenv(*curr++);
 
399
                }
 
400
                i++;
 
401
        }
310
402
        return envp;
311
403
}
312
404
 
399
491
        if (client_config.fqdn)
400
492
                udhcp_add_binary_option(packet, client_config.fqdn);
401
493
 
 
494
        /* Request broadcast replies if we have no IP addr */
 
495
        if ((option_mask32 & OPT_B) && packet->ciaddr == 0)
 
496
                packet->flags |= htons(BROADCAST_FLAG);
 
497
 
402
498
        /* Add -x options if any */
403
499
        {
404
500
                struct option_set *curr = client_config.options;
722
818
         *
723
819
         * TODO: make conditional?
724
820
         */
725
 
#define SERVER_AND_CLIENT_PORTS  ((67 << 16) + 68)
726
821
        static const struct sock_filter filter_instr[] = {
727
 
                /* check for udp */
 
822
                /* load 9th byte (protocol) */
728
823
                BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
729
 
                BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0),     /* L5, L1, is UDP? */
730
 
                /* ugly check for arp on ethernet-like and IPv4 */
731
 
                BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),                      /* L1: */
732
 
                BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4),      /* L3, L4 */
733
 
                /* skip IP header */
734
 
                BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),                     /* L5: */
735
 
                /* check udp source and destination ports */
736
 
                BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0),
737
 
                BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1), /* L3, L4 */
738
 
                /* returns */
739
 
                BPF_STMT(BPF_RET|BPF_K, 0x0fffffff ),                   /* L3: pass */
740
 
                BPF_STMT(BPF_RET|BPF_K, 0),                             /* L4: reject */
 
824
                /* jump to L1 if it is IPPROTO_UDP, else to L4 */
 
825
                BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
 
826
                /* L1: load halfword from offset 6 (flags and frag offset) */
 
827
                BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
 
828
                /* jump to L4 if any bits in frag offset field are set, else to L2 */
 
829
                BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
 
830
                /* L2: skip IP header (load index reg with header len) */
 
831
                BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),
 
832
                /* load udp destination port from halfword[header_len + 2] */
 
833
                BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
 
834
                /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */
 
835
                BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
 
836
                /* L3: accept packet */
 
837
                BPF_STMT(BPF_RET|BPF_K, 0xffffffff),
 
838
                /* L4: discard packet */
 
839
                BPF_STMT(BPF_RET|BPF_K, 0),
741
840
        };
742
841
        static const struct sock_fprog filter_prog = {
743
842
                .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
750
849
        fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
751
850
        log1("Got raw socket fd %d", fd); //log2?
752
851
 
753
 
        if (SERVER_PORT == 67 && CLIENT_PORT == 68) {
754
 
                /* Use only if standard ports are in use */
 
852
        sock.sll_family = AF_PACKET;
 
853
        sock.sll_protocol = htons(ETH_P_IP);
 
854
        sock.sll_ifindex = ifindex;
 
855
        xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
 
856
 
 
857
        if (CLIENT_PORT == 68) {
 
858
                /* Use only if standard port is in use */
755
859
                /* Ignoring error (kernel may lack support for this) */
756
860
                if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
757
861
                                sizeof(filter_prog)) >= 0)
758
862
                        log1("Attached filter to raw socket fd %d", fd); // log?
759
863
        }
760
864
 
761
 
        sock.sll_family = AF_PACKET;
762
 
        sock.sll_protocol = htons(ETH_P_IP);
763
 
        sock.sll_ifindex = ifindex;
764
 
        xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
765
865
        log1("Created raw socket");
766
866
 
767
867
        return fd;
858
958
//usage:# define IF_UDHCP_VERBOSE(...)
859
959
//usage:#endif
860
960
//usage:#define udhcpc_trivial_usage
861
 
//usage:       "[-fbnq"IF_UDHCP_VERBOSE("v")"oCR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n"
 
961
//usage:       "[-fbnq"IF_UDHCP_VERBOSE("v")"oCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n"
862
962
//usage:       "        [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
863
963
//usage:#define udhcpc_full_usage "\n"
864
964
//usage:        IF_LONG_OPTS(
865
965
//usage:     "\n        -i,--interface IFACE    Interface to use (default eth0)"
866
966
//usage:     "\n        -p,--pidfile FILE       Create pidfile"
867
967
//usage:     "\n        -s,--script PROG        Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
 
968
//usage:     "\n        -B,--broadcast          Request broadcast replies"
868
969
//usage:     "\n        -t,--retries N          Send up to N discover packets"
869
970
//usage:     "\n        -T,--timeout N          Pause between packets (default 3 seconds)"
870
971
//usage:     "\n        -A,--tryagain N         Wait N seconds after failure (default 20)"
902
1003
//usage:     "\n        -i IFACE        Interface to use (default eth0)"
903
1004
//usage:     "\n        -p FILE         Create pidfile"
904
1005
//usage:     "\n        -s PROG         Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
 
1006
//usage:     "\n        -B              Request broadcast replies"
905
1007
//usage:     "\n        -t N            Send up to N discover packets"
906
1008
//usage:     "\n        -T N            Pause between packets (default 3 seconds)"
907
1009
//usage:     "\n        -A N            Wait N seconds (default 20) after failure"
935
1037
//usage:     "\n        -v              Verbose"
936
1038
//usage:        )
937
1039
//usage:        )
 
1040
//usage:     "\nSignals:"
 
1041
//usage:     "\n        USR1    Renew current lease"
 
1042
//usage:     "\n        USR2    Release current lease"
 
1043
 
938
1044
 
939
1045
int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
940
1046
int udhcpc_main(int argc UNUSED_PARAM, char **argv)
962
1068
        struct dhcp_packet packet;
963
1069
        fd_set rfds;
964
1070
 
965
 
#if ENABLE_LONG_OPTS
966
 
        static const char udhcpc_longopts[] ALIGN1 =
967
 
                "clientid-none\0"  No_argument       "C"
968
 
                "vendorclass\0"    Required_argument "V"
969
 
                "hostname\0"       Required_argument "H"
970
 
                "fqdn\0"           Required_argument "F"
971
 
                "interface\0"      Required_argument "i"
972
 
                "now\0"            No_argument       "n"
973
 
                "pidfile\0"        Required_argument "p"
974
 
                "quit\0"           No_argument       "q"
975
 
                "release\0"        No_argument       "R"
976
 
                "request\0"        Required_argument "r"
977
 
                "script\0"         Required_argument "s"
978
 
                "timeout\0"        Required_argument "T"
979
 
                "version\0"        No_argument       "v"
980
 
                "retries\0"        Required_argument "t"
981
 
                "tryagain\0"       Required_argument "A"
982
 
                "syslog\0"         No_argument       "S"
983
 
                "request-option\0" Required_argument "O"
984
 
                "no-default-options\0" No_argument   "o"
985
 
                "foreground\0"     No_argument       "f"
986
 
                "background\0"     No_argument       "b"
987
 
                IF_FEATURE_UDHCPC_ARPING("arping\0"     No_argument       "a")
988
 
                IF_FEATURE_UDHCP_PORT("client-port\0"   Required_argument "P")
989
 
                ;
990
 
#endif
991
 
        enum {
992
 
                OPT_C = 1 << 0,
993
 
                OPT_V = 1 << 1,
994
 
                OPT_H = 1 << 2,
995
 
                OPT_h = 1 << 3,
996
 
                OPT_F = 1 << 4,
997
 
                OPT_i = 1 << 5,
998
 
                OPT_n = 1 << 6,
999
 
                OPT_p = 1 << 7,
1000
 
                OPT_q = 1 << 8,
1001
 
                OPT_R = 1 << 9,
1002
 
                OPT_r = 1 << 10,
1003
 
                OPT_s = 1 << 11,
1004
 
                OPT_T = 1 << 12,
1005
 
                OPT_t = 1 << 13,
1006
 
                OPT_S = 1 << 14,
1007
 
                OPT_A = 1 << 15,
1008
 
                OPT_O = 1 << 16,
1009
 
                OPT_o = 1 << 17,
1010
 
                OPT_x = 1 << 18,
1011
 
                OPT_f = 1 << 19,
1012
 
/* The rest has variable bit positions, need to be clever */
1013
 
                OPTBIT_f = 19,
1014
 
                USE_FOR_MMU(             OPTBIT_b,)
1015
 
                IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
1016
 
                IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
1017
 
                USE_FOR_MMU(             OPT_b = 1 << OPTBIT_b,)
1018
 
                IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
1019
 
                IF_FEATURE_UDHCP_PORT(   OPT_P = 1 << OPTBIT_P,)
1020
 
        };
1021
 
 
1022
1071
        /* Default options */
1023
1072
        IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
1024
1073
        IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
1034
1083
#endif
1035
1084
                ;
1036
1085
        IF_LONG_OPTS(applet_long_options = udhcpc_longopts;)
1037
 
        opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:f"
 
1086
        opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB"
1038
1087
                USE_FOR_MMU("b")
1039
1088
                IF_FEATURE_UDHCPC_ARPING("a")
1040
1089
                IF_FEATURE_UDHCP_PORT("P:")
1079
1128
                client_config.no_default_options = 1;
1080
1129
        while (list_O) {
1081
1130
                char *optstr = llist_pop(&list_O);
1082
 
                unsigned n = udhcp_option_idx(optstr);
1083
 
                n = dhcp_optflags[n].code;
 
1131
                unsigned n = bb_strtou(optstr, NULL, 0);
 
1132
                if (errno || n > 254) {
 
1133
                        n = udhcp_option_idx(optstr);
 
1134
                        n = dhcp_optflags[n].code;
 
1135
                }
1084
1136
                client_config.opt_mask[n >> 3] |= 1 << (n & 7);
1085
1137
        }
1086
1138
        while (list_x) {