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>
33
# include <linux/if_packet.h>
34
# include <linux/if_ether.h>
28
#include <netinet/if_ether.h>
29
#include <netpacket/packet.h>
36
30
#include <linux/filter.h>
38
32
/* struct client_config_t client_config is in bb_common_bufsiz1 */
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")
62
/* Must match getopt32 option string order */
85
/* The rest has variable bit positions, need to be clever */
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,)
41
96
/*** Script execution code ***/
43
98
/* get a rough idea of how long an option will be (rounding up...) */
240
295
uint8_t overload = 0;
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];
303
memset(found_opts, 0, sizeof(found_opts));
242
305
/* We need 6 elements for:
243
306
* "interface=IFACE"
244
307
* "ip=N.N.N.N" from packet->yiaddr
251
314
/* +1 element for each option, +2 for subnet option: */
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);
320
if (i == DHCP_OPTION_OVERLOAD)
322
else if (i == DHCP_SUBNET)
256
323
envc++; /* for mton */
325
/*if (i != DHCP_MESSAGE_TYPE)*/
326
FOUND_OPTS(i) |= BMASK(i);
260
temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD);
264
curr = envp = xzalloc(sizeof(char *) * envc);
330
curr = envp = xzalloc(sizeof(envp[0]) * envc);
266
332
*curr = xasprintf("interface=%s", client_config.interface);
276
342
opt_name = dhcp_option_strings;
278
344
while (*opt_name) {
279
temp = udhcp_get_option(packet, dhcp_optflags[i].code);
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))
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);
284
if (dhcp_optflags[i].code == DHCP_SUBNET) {
354
if (code == DHCP_SUBNET) {
285
355
/* Subnet option: make things like "$ip/$mask" possible */
287
357
move_from_unaligned32(subnet, temp);
307
377
*curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname);
380
/* Handle unknown options */
381
for (i = 0; i < 256;) {
382
BITMAP bitmap = FOUND_OPTS(i);
387
if (bitmap & BMASK(i)) {
390
temp = udhcp_get_option(packet, i);
391
/* udhcp_get_option returns ptr to data portion,
392
* need to go back to get len
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';
723
819
* TODO: make conditional?
725
#define SERVER_AND_CLIENT_PORTS ((67 << 16) + 68)
726
821
static const struct sock_filter filter_instr[] = {
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 */
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 */
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),
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?
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));
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?
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");
858
958
//usage:# define IF_UDHCP_VERBOSE(...)
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)"
962
1068
struct dhcp_packet packet;
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")
1012
/* The rest has variable bit positions, need to be clever */
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,)
1022
1071
/* Default options */
1023
1072
IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
1024
1073
IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
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;
1084
1136
client_config.opt_mask[n >> 3] |= 1 << (n & 7);
1086
1138
while (list_x) {