|
|
|
@ -33,25 +33,8 @@ static int fd = -1;
|
|
|
|
|
#define LISTEN_RAW 2
|
|
|
|
|
static int listen_mode;
|
|
|
|
|
|
|
|
|
|
struct client_config_t client_config = {
|
|
|
|
|
/* Default options. */
|
|
|
|
|
.abort_if_no_lease = 0,
|
|
|
|
|
.foreground = 0,
|
|
|
|
|
.quit_after_lease = 0,
|
|
|
|
|
.release_on_quit = 0,
|
|
|
|
|
.background_if_no_lease = 0,
|
|
|
|
|
.interface = "eth0",
|
|
|
|
|
.pidfile = NULL,
|
|
|
|
|
.script = DEFAULT_SCRIPT,
|
|
|
|
|
.clientid = NULL,
|
|
|
|
|
.vendorclass = NULL,
|
|
|
|
|
.hostname = NULL,
|
|
|
|
|
.fqdn = NULL,
|
|
|
|
|
.ifindex = 0,
|
|
|
|
|
.retries = 3,
|
|
|
|
|
.timeout = 3,
|
|
|
|
|
.arp = "\0\0\0\0\0\0", /* appease gcc-3.0 */
|
|
|
|
|
};
|
|
|
|
|
struct client_config_t client_config;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* just a little helper */
|
|
|
|
|
static void change_mode(int new_mode)
|
|
|
|
@ -126,139 +109,137 @@ static void client_background(void)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
|
|
|
|
|
{
|
|
|
|
|
uint8_t *storage;
|
|
|
|
|
int len = strlen(str);
|
|
|
|
|
if (len > 255) len = 255;
|
|
|
|
|
storage = xzalloc(len + extra + OPT_DATA);
|
|
|
|
|
storage[OPT_CODE] = code;
|
|
|
|
|
storage[OPT_LEN] = len + extra;
|
|
|
|
|
memcpy(storage + extra + OPT_DATA, str, len);
|
|
|
|
|
return storage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int udhcpc_main(int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
uint8_t *temp, *message;
|
|
|
|
|
char *str_c, *str_V, *str_h, *str_F, *str_r, *str_T, *str_t;
|
|
|
|
|
unsigned long t1 = 0, t2 = 0, xid = 0;
|
|
|
|
|
unsigned long start = 0, lease = 0;
|
|
|
|
|
fd_set rfds;
|
|
|
|
|
int retval;
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
int c, len;
|
|
|
|
|
struct dhcpMessage packet;
|
|
|
|
|
struct in_addr temp_addr;
|
|
|
|
|
long now;
|
|
|
|
|
unsigned opt;
|
|
|
|
|
int max_fd;
|
|
|
|
|
int sig;
|
|
|
|
|
int retval;
|
|
|
|
|
int len;
|
|
|
|
|
int no_clientid = 0;
|
|
|
|
|
fd_set rfds;
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
struct dhcpMessage packet;
|
|
|
|
|
struct in_addr temp_addr;
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
OPT_c = 1 << 0,
|
|
|
|
|
OPT_C = 1 << 1,
|
|
|
|
|
OPT_V = 1 << 2,
|
|
|
|
|
OPT_f = 1 << 3,
|
|
|
|
|
OPT_b = 1 << 4,
|
|
|
|
|
OPT_H = 1 << 5,
|
|
|
|
|
OPT_h = 1 << 6,
|
|
|
|
|
OPT_F = 1 << 7,
|
|
|
|
|
OPT_i = 1 << 8,
|
|
|
|
|
OPT_n = 1 << 9,
|
|
|
|
|
OPT_p = 1 << 10,
|
|
|
|
|
OPT_q = 1 << 11,
|
|
|
|
|
OPT_R = 1 << 12,
|
|
|
|
|
OPT_r = 1 << 13,
|
|
|
|
|
OPT_s = 1 << 14,
|
|
|
|
|
OPT_T = 1 << 15,
|
|
|
|
|
OPT_t = 1 << 16,
|
|
|
|
|
OPT_v = 1 << 17,
|
|
|
|
|
};
|
|
|
|
|
static const struct option arg_options[] = {
|
|
|
|
|
{"clientid", required_argument, 0, 'c'},
|
|
|
|
|
{"clientid-none", no_argument, 0, 'C'},
|
|
|
|
|
{"vendorclass", required_argument, 0, 'V'},
|
|
|
|
|
{"foreground", no_argument, 0, 'f'},
|
|
|
|
|
{"background", no_argument, 0, 'b'},
|
|
|
|
|
{"hostname", required_argument, 0, 'H'},
|
|
|
|
|
{"hostname", required_argument, 0, 'h'},
|
|
|
|
|
{"fqdn", required_argument, 0, 'F'},
|
|
|
|
|
{"interface", required_argument, 0, 'i'},
|
|
|
|
|
{"now", no_argument, 0, 'n'},
|
|
|
|
|
{"pidfile", required_argument, 0, 'p'},
|
|
|
|
|
{"quit", no_argument, 0, 'q'},
|
|
|
|
|
{"release", no_argument, 0, 'R'},
|
|
|
|
|
{"request", required_argument, 0, 'r'},
|
|
|
|
|
{"script", required_argument, 0, 's'},
|
|
|
|
|
{"timeout", required_argument, 0, 'T'},
|
|
|
|
|
{"version", no_argument, 0, 'v'},
|
|
|
|
|
{"retries", required_argument, 0, 't'},
|
|
|
|
|
{0, 0, 0, 0}
|
|
|
|
|
{ "clientid", required_argument, 0, 'c' },
|
|
|
|
|
{ "clientid-none", no_argument, 0, 'C' },
|
|
|
|
|
{ "vendorclass", required_argument, 0, 'V' },
|
|
|
|
|
{ "foreground", no_argument, 0, 'f' },
|
|
|
|
|
{ "background", no_argument, 0, 'b' },
|
|
|
|
|
{ "hostname", required_argument, 0, 'H' },
|
|
|
|
|
{ "hostname", required_argument, 0, 'h' },
|
|
|
|
|
{ "fqdn", required_argument, 0, 'F' },
|
|
|
|
|
{ "interface", required_argument, 0, 'i' },
|
|
|
|
|
{ "now", no_argument, 0, 'n' },
|
|
|
|
|
{ "pidfile", required_argument, 0, 'p' },
|
|
|
|
|
{ "quit", no_argument, 0, 'q' },
|
|
|
|
|
{ "release", no_argument, 0, 'R' },
|
|
|
|
|
{ "request", required_argument, 0, 'r' },
|
|
|
|
|
{ "script", required_argument, 0, 's' },
|
|
|
|
|
{ "timeout", required_argument, 0, 'T' },
|
|
|
|
|
{ "version", no_argument, 0, 'v' },
|
|
|
|
|
{ "retries", required_argument, 0, 't' },
|
|
|
|
|
{ 0, 0, 0, 0 }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* get options */
|
|
|
|
|
while (1) {
|
|
|
|
|
int option_index = 0;
|
|
|
|
|
c = getopt_long(argc, argv, "c:CV:fbH:h:F:i:np:qRr:s:T:t:v", arg_options, &option_index);
|
|
|
|
|
if (c == -1) break;
|
|
|
|
|
/* Default options. */
|
|
|
|
|
client_config.interface = "eth0";
|
|
|
|
|
client_config.script = DEFAULT_SCRIPT;
|
|
|
|
|
client_config.retries = 3;
|
|
|
|
|
client_config.timeout = 3;
|
|
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
case 'c':
|
|
|
|
|
if (no_clientid) bb_show_usage();
|
|
|
|
|
len = strlen(optarg) > 255 ? 255 : strlen(optarg);
|
|
|
|
|
free(client_config.clientid);
|
|
|
|
|
client_config.clientid = xmalloc(len + 2);
|
|
|
|
|
client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
|
|
|
|
|
client_config.clientid[OPT_LEN] = len;
|
|
|
|
|
client_config.clientid[OPT_DATA] = '\0';
|
|
|
|
|
strncpy((char*)client_config.clientid + OPT_DATA, optarg, len);
|
|
|
|
|
break;
|
|
|
|
|
case 'C':
|
|
|
|
|
if (client_config.clientid) bb_show_usage();
|
|
|
|
|
/* Parse command line */
|
|
|
|
|
opt_complementary = "?:c--C:C--c" // mutually exclusive
|
|
|
|
|
":hH:Hh"; // -h and -H are the same
|
|
|
|
|
applet_long_options = arg_options;
|
|
|
|
|
opt = getopt32(argc, argv, "c:CV:fbH:h:F:i:np:qRr:s:T:t:v",
|
|
|
|
|
&str_c, &str_V, &str_h, &str_h, &str_F,
|
|
|
|
|
&client_config.interface, &client_config.pidfile, &str_r,
|
|
|
|
|
&client_config.script, &str_T, &str_t
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (opt & OPT_c)
|
|
|
|
|
client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0);
|
|
|
|
|
if (opt & OPT_C)
|
|
|
|
|
no_clientid = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'V':
|
|
|
|
|
len = strlen(optarg) > 255 ? 255 : strlen(optarg);
|
|
|
|
|
free(client_config.vendorclass);
|
|
|
|
|
client_config.vendorclass = xmalloc(len + 2);
|
|
|
|
|
client_config.vendorclass[OPT_CODE] = DHCP_VENDOR;
|
|
|
|
|
client_config.vendorclass[OPT_LEN] = len;
|
|
|
|
|
strncpy((char*)client_config.vendorclass + OPT_DATA, optarg, len);
|
|
|
|
|
break;
|
|
|
|
|
case 'f':
|
|
|
|
|
if (opt & OPT_V)
|
|
|
|
|
client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
|
|
|
|
|
if (opt & OPT_f)
|
|
|
|
|
client_config.foreground = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'b':
|
|
|
|
|
if (opt & OPT_b)
|
|
|
|
|
client_config.background_if_no_lease = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'h':
|
|
|
|
|
case 'H':
|
|
|
|
|
len = strlen(optarg) > 255 ? 255 : strlen(optarg);
|
|
|
|
|
free(client_config.hostname);
|
|
|
|
|
client_config.hostname = xmalloc(len + 2);
|
|
|
|
|
client_config.hostname[OPT_CODE] = DHCP_HOST_NAME;
|
|
|
|
|
client_config.hostname[OPT_LEN] = len;
|
|
|
|
|
strncpy((char*)client_config.hostname + 2, optarg, len);
|
|
|
|
|
break;
|
|
|
|
|
case 'F':
|
|
|
|
|
len = strlen(optarg) > 255 ? 255 : strlen(optarg);
|
|
|
|
|
free(client_config.fqdn);
|
|
|
|
|
client_config.fqdn = xmalloc(len + 5);
|
|
|
|
|
client_config.fqdn[OPT_CODE] = DHCP_FQDN;
|
|
|
|
|
client_config.fqdn[OPT_LEN] = len + 3;
|
|
|
|
|
if (opt & OPT_h)
|
|
|
|
|
client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
|
|
|
|
|
if (opt & OPT_F) {
|
|
|
|
|
client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3);
|
|
|
|
|
/* Flags: 0000NEOS
|
|
|
|
|
S: 1 => Client requests Server to update A RR in DNS as well as PTR
|
|
|
|
|
O: 1 => Server indicates to client that DNS has been updated regardless
|
|
|
|
|
E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com"
|
|
|
|
|
N: 1 => Client requests Server to not update DNS
|
|
|
|
|
*/
|
|
|
|
|
client_config.fqdn[OPT_LEN + 1] = 0x1;
|
|
|
|
|
client_config.fqdn[OPT_LEN + 2] = 0;
|
|
|
|
|
client_config.fqdn[OPT_LEN + 3] = 0;
|
|
|
|
|
strncpy((char*)client_config.fqdn + 5, optarg, len);
|
|
|
|
|
break;
|
|
|
|
|
case 'i':
|
|
|
|
|
client_config.interface = optarg;
|
|
|
|
|
break;
|
|
|
|
|
case 'n':
|
|
|
|
|
client_config.fqdn[OPT_DATA + 0] = 0x1;
|
|
|
|
|
/* client_config.fqdn[OPT_DATA + 1] = 0; - redundant */
|
|
|
|
|
/* client_config.fqdn[OPT_DATA + 2] = 0; - redundant */
|
|
|
|
|
}
|
|
|
|
|
// if (opt & OPT_i) client_config.interface = ...
|
|
|
|
|
if (opt & OPT_n)
|
|
|
|
|
client_config.abort_if_no_lease = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'p':
|
|
|
|
|
client_config.pidfile = optarg;
|
|
|
|
|
break;
|
|
|
|
|
case 'q':
|
|
|
|
|
// if (opt & OPT_p) client_config.pidfile = ...
|
|
|
|
|
if (opt & OPT_q)
|
|
|
|
|
client_config.quit_after_lease = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'R':
|
|
|
|
|
if (opt & OPT_R)
|
|
|
|
|
client_config.release_on_quit = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'r':
|
|
|
|
|
requested_ip = inet_addr(optarg);
|
|
|
|
|
break;
|
|
|
|
|
case 's':
|
|
|
|
|
client_config.script = optarg;
|
|
|
|
|
break;
|
|
|
|
|
case 'T':
|
|
|
|
|
client_config.timeout = xatoi_u(optarg);
|
|
|
|
|
break;
|
|
|
|
|
case 't':
|
|
|
|
|
client_config.retries = xatoi_u(optarg);
|
|
|
|
|
break;
|
|
|
|
|
case 'v':
|
|
|
|
|
if (opt & OPT_r)
|
|
|
|
|
requested_ip = inet_addr(str_r);
|
|
|
|
|
// if (opt & OPT_s) client_config.script = ...
|
|
|
|
|
if (opt & OPT_T)
|
|
|
|
|
client_config.timeout = xatoi_u(str_T);
|
|
|
|
|
if (opt & OPT_t)
|
|
|
|
|
client_config.retries = xatoi_u(str_t);
|
|
|
|
|
if (opt & OPT_v) {
|
|
|
|
|
printf("version %s\n\n", BB_VER);
|
|
|
|
|
return 0;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
bb_show_usage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Start the log, sanitize fd's, and write a pid file */
|
|
|
|
@ -270,22 +251,13 @@ int udhcpc_main(int argc, char *argv[])
|
|
|
|
|
|
|
|
|
|
/* if not set, and not suppressed, setup the default client ID */
|
|
|
|
|
if (!client_config.clientid && !no_clientid) {
|
|
|
|
|
client_config.clientid = xmalloc(6 + 3);
|
|
|
|
|
client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
|
|
|
|
|
client_config.clientid[OPT_LEN] = 7;
|
|
|
|
|
client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
|
|
|
|
|
client_config.clientid[OPT_DATA] = 1;
|
|
|
|
|
memcpy(client_config.clientid + 3, client_config.arp, 6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!client_config.vendorclass) {
|
|
|
|
|
client_config.vendorclass = xmalloc(sizeof("udhcp "BB_VER) + 2);
|
|
|
|
|
client_config.vendorclass[OPT_CODE] = DHCP_VENDOR;
|
|
|
|
|
client_config.vendorclass[OPT_LEN] = sizeof("udhcp "BB_VER) - 1;
|
|
|
|
|
client_config.vendorclass[OPT_DATA] = 1;
|
|
|
|
|
memcpy(&client_config.vendorclass[OPT_DATA],
|
|
|
|
|
"udhcp "BB_VER, sizeof("udhcp "BB_VER) - 1);
|
|
|
|
|
memcpy(client_config.clientid + OPT_DATA+1, client_config.arp, 6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!client_config.vendorclass)
|
|
|
|
|
client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, "udhcp "BB_VER, 0);
|
|
|
|
|
|
|
|
|
|
/* setup the signal pipe */
|
|
|
|
|
udhcp_sp_setup();
|
|
|
|
@ -295,7 +267,6 @@ int udhcpc_main(int argc, char *argv[])
|
|
|
|
|
change_mode(LISTEN_RAW);
|
|
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
|
|
|
|
|
tv.tv_sec = timeout - uptime();
|
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
|
|
|
|
|
|