Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/networking/udhcp/files.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/networking/udhcp/files.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 2 /* 3 * files.c -- DHCP server file manipulation * 3 * DHCP server config and lease file manipulation 4 * 4 5 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001 6 * 7 * Licensed under GPLv2, see file LICENSE in this source tree. 5 8 */ 6 7 9 #include <netinet/ether.h> 8 10 9 11 #include "common.h" 10 12 #include "dhcpd.h" 11 #include "options.h"12 13 13 14 14 /* on these functions, make sure your datatype matches */ 15 static int read_ip(const char *line, void *arg) 16 { 17 len_and_sockaddr *lsa; 18 19 lsa = host_and_af2sockaddr(line, 0, AF_INET); 20 if (!lsa) 21 return 0; 22 *(uint32_t*)arg = lsa->sin.sin_addr.s_addr; 23 free(lsa); 24 return 1; 25 } 26 27 static int read_mac(const char *line, void *arg) 28 { 29 uint8_t *mac_bytes = arg; 30 struct ether_addr *temp_ether_addr; 31 32 temp_ether_addr = ether_aton(line); 33 if (temp_ether_addr == NULL) 34 return 0; 35 memcpy(mac_bytes, temp_ether_addr, 6); 36 return 1; 37 } 38 39 40 static int read_str(const char *line, void *arg) 15 static int FAST_FUNC read_str(const char *line, void *arg) 41 16 { 42 17 char **dest = arg; … … 47 22 } 48 23 49 50 static int read_u32(const char *line, void *arg) 24 static int FAST_FUNC read_u32(const char *line, void *arg) 51 25 { 52 26 *(uint32_t*)arg = bb_strtou32(line, NULL, 10); … … 54 28 } 55 29 56 57 static int read_yn(const char *line, void *arg) 58 { 59 char *dest = arg; 60 61 if (!strcasecmp("yes", line)) { 62 *dest = 1; 63 return 1; 64 } 65 if (!strcasecmp("no", line)) { 66 *dest = 0; 67 return 1; 68 } 69 return 0; 70 } 71 72 73 /* find option 'code' in opt_list */ 74 struct option_set *find_option(struct option_set *opt_list, char code) 75 { 76 while (opt_list && opt_list->data[OPT_CODE] < code) 77 opt_list = opt_list->next; 78 79 if (opt_list && opt_list->data[OPT_CODE] == code) 80 return opt_list; 81 return NULL; 82 } 83 84 85 /* add an option to the opt_list */ 86 static void attach_option(struct option_set **opt_list, 87 const struct dhcp_option *option, char *buffer, int length) 88 { 89 struct option_set *existing, *new, **curr; 90 91 existing = find_option(*opt_list, option->code); 92 if (!existing) { 93 DEBUG("Attaching option %s to list", option->name); 94 95 #if ENABLE_FEATURE_RFC3397 96 if ((option->flags & TYPE_MASK) == OPTION_STR1035) 97 /* reuse buffer and length for RFC1035-formatted string */ 98 buffer = dname_enc(NULL, 0, buffer, &length); 99 #endif 100 101 /* make a new option */ 102 new = xmalloc(sizeof(*new)); 103 new->data = xmalloc(length + 2); 104 new->data[OPT_CODE] = option->code; 105 new->data[OPT_LEN] = length; 106 memcpy(new->data + 2, buffer, length); 107 108 curr = opt_list; 109 while (*curr && (*curr)->data[OPT_CODE] < option->code) 110 curr = &(*curr)->next; 111 112 new->next = *curr; 113 *curr = new; 114 #if ENABLE_FEATURE_RFC3397 115 if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL) 116 free(buffer); 117 #endif 118 return; 119 } 120 121 /* add it to an existing option */ 122 DEBUG("Attaching option %s to existing member of list", option->name); 123 if (option->flags & OPTION_LIST) { 124 #if ENABLE_FEATURE_RFC3397 125 if ((option->flags & TYPE_MASK) == OPTION_STR1035) 126 /* reuse buffer and length for RFC1035-formatted string */ 127 buffer = dname_enc(existing->data + 2, 128 existing->data[OPT_LEN], buffer, &length); 129 #endif 130 if (existing->data[OPT_LEN] + length <= 255) { 131 existing->data = xrealloc(existing->data, 132 existing->data[OPT_LEN] + length + 3); 133 if ((option->flags & TYPE_MASK) == OPTION_STRING) { 134 /* ' ' can bring us to 256 - bad */ 135 if (existing->data[OPT_LEN] + length >= 255) 136 return; 137 /* add space separator between STRING options in a list */ 138 existing->data[existing->data[OPT_LEN] + 2] = ' '; 139 existing->data[OPT_LEN]++; 140 } 141 memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length); 142 existing->data[OPT_LEN] += length; 143 } /* else, ignore the data, we could put this in a second option in the future */ 144 #if ENABLE_FEATURE_RFC3397 145 if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL) 146 free(buffer); 147 #endif 148 } /* else, ignore the new data */ 149 } 150 151 152 /* read a dhcp option and add it to opt_list */ 153 static int read_opt(const char *const_line, void *arg) 154 { 155 struct option_set **opt_list = arg; 156 char *opt, *val, *endptr; 157 const struct dhcp_option *option; 158 int retval = 0, length; 159 char buffer[8]; 160 char *line; 161 uint16_t *result_u16 = (uint16_t *) buffer; 162 uint32_t *result_u32 = (uint32_t *) buffer; 163 164 /* Cheat, the only const line we'll actually get is "" */ 165 line = (char *) const_line; 166 opt = strtok(line, " \t="); 167 if (!opt) return 0; 168 169 option = dhcp_options; 170 while (1) { 171 if (!option->code) 172 return 0; 173 if (!strcasecmp(option->name, opt)) 174 break; 175 option++; 176 } 177 178 do { 179 val = strtok(NULL, ", \t"); 180 if (!val) break; 181 length = option_lengths[option->flags & TYPE_MASK]; 182 retval = 0; 183 opt = buffer; /* new meaning for variable opt */ 184 switch (option->flags & TYPE_MASK) { 185 case OPTION_IP: 186 retval = read_ip(val, buffer); 187 break; 188 case OPTION_IP_PAIR: 189 retval = read_ip(val, buffer); 190 val = strtok(NULL, ", \t/-"); 191 if (!val) 192 retval = 0; 193 if (retval) 194 retval = read_ip(val, buffer + 4); 195 break; 196 case OPTION_STRING: 197 #if ENABLE_FEATURE_RFC3397 198 case OPTION_STR1035: 199 #endif 200 length = strlen(val); 201 if (length > 0) { 202 if (length > 254) length = 254; 203 opt = val; 204 retval = 1; 205 } 206 break; 207 case OPTION_BOOLEAN: 208 retval = read_yn(val, buffer); 209 break; 210 case OPTION_U8: 211 buffer[0] = strtoul(val, &endptr, 0); 212 retval = (endptr[0] == '\0'); 213 break; 214 /* htonX are macros in older libc's, using temp var 215 * in code below for safety */ 216 /* TODO: use bb_strtoX? */ 217 case OPTION_U16: { 218 unsigned long tmp = strtoul(val, &endptr, 0); 219 *result_u16 = htons(tmp); 220 retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/); 221 break; 222 } 223 case OPTION_S16: { 224 long tmp = strtol(val, &endptr, 0); 225 *result_u16 = htons(tmp); 226 retval = (endptr[0] == '\0'); 227 break; 228 } 229 case OPTION_U32: { 230 unsigned long tmp = strtoul(val, &endptr, 0); 231 *result_u32 = htonl(tmp); 232 retval = (endptr[0] == '\0'); 233 break; 234 } 235 case OPTION_S32: { 236 long tmp = strtol(val, &endptr, 0); 237 *result_u32 = htonl(tmp); 238 retval = (endptr[0] == '\0'); 239 break; 240 } 241 default: 242 break; 243 } 244 if (retval) 245 attach_option(opt_list, option, opt, length); 246 } while (retval && option->flags & OPTION_LIST); 247 return retval; 248 } 249 250 static int read_staticlease(const char *const_line, void *arg) 30 static int FAST_FUNC read_staticlease(const char *const_line, void *arg) 251 31 { 252 32 char *line; 253 33 char *mac_string; 254 34 char *ip_string; 255 uint8_t *mac_bytes; 256 uint32_t *ip; 257 258 /* Allocate memory for addresses */ 259 mac_bytes = xmalloc(sizeof(unsigned char) * 8); 260 ip = xmalloc(sizeof(uint32_t)); 35 struct ether_addr mac_bytes; /* it's "struct { uint8_t mac[6]; }" */ 36 uint32_t nip; 261 37 262 38 /* Read mac */ 263 39 line = (char *) const_line; 264 mac_string = strtok(line, " \t"); 265 read_mac(mac_string, mac_bytes); 40 mac_string = strtok_r(line, " \t", &line); 41 if (!mac_string || !ether_aton_r(mac_string, &mac_bytes)) 42 return 0; 266 43 267 44 /* Read ip */ 268 ip_string = strtok(NULL, " \t"); 269 read_ip(ip_string, ip); 270 271 addStaticLease(arg, mac_bytes, ip); 272 273 if (ENABLE_FEATURE_UDHCP_DEBUG) printStaticLeases(arg); 45 ip_string = strtok_r(NULL, " \t", &line); 46 if (!ip_string || !udhcp_str2nip(ip_string, &nip)) 47 return 0; 48 49 add_static_lease(arg, (uint8_t*) &mac_bytes, nip); 50 51 log_static_leases(arg); 274 52 275 53 return 1; … … 279 57 struct config_keyword { 280 58 const char *keyword; 281 int (*handler)(const char *line, void *var) ;59 int (*handler)(const char *line, void *var) FAST_FUNC; 282 60 void *var; 283 61 const char *def; … … 285 63 286 64 static const struct config_keyword keywords[] = { 287 /* keyword handler variable address default */ 288 {"start", read_ip, &(server_config.start_ip), "192.168.0.20"}, 289 {"end", read_ip, &(server_config.end_ip), "192.168.0.254"}, 290 {"interface", read_str, &(server_config.interface), "eth0"}, 291 {"option", read_opt, &(server_config.options), ""}, 292 {"opt", read_opt, &(server_config.options), ""}, 65 /* keyword handler variable address default */ 66 {"start" , udhcp_str2nip , &server_config.start_ip , "192.168.0.20"}, 67 {"end" , udhcp_str2nip , &server_config.end_ip , "192.168.0.254"}, 68 {"interface" , read_str , &server_config.interface , "eth0"}, 293 69 /* Avoid "max_leases value not sane" warning by setting default 294 70 * to default_end_ip - default_start_ip + 1: */ 295 {"max_leases", read_u32, &(server_config.max_leases), "235"}, 296 {"remaining", read_yn, &(server_config.remaining), "yes"}, 297 {"auto_time", read_u32, &(server_config.auto_time), "7200"}, 298 {"decline_time", read_u32, &(server_config.decline_time), "3600"}, 299 {"conflict_time",read_u32, &(server_config.conflict_time),"3600"}, 300 {"offer_time", read_u32, &(server_config.offer_time), "60"}, 301 {"min_lease", read_u32, &(server_config.min_lease), "60"}, 302 {"lease_file", read_str, &(server_config.lease_file), LEASES_FILE}, 303 {"pidfile", read_str, &(server_config.pidfile), "/var/run/udhcpd.pid"}, 304 {"notify_file", read_str, &(server_config.notify_file), ""}, 305 {"siaddr", read_ip, &(server_config.siaddr), "0.0.0.0"}, 306 {"sname", read_str, &(server_config.sname), ""}, 307 {"boot_file", read_str, &(server_config.boot_file), ""}, 308 {"static_lease", read_staticlease, &(server_config.static_leases), ""}, 309 /* ADDME: static lease */ 71 {"max_leases" , read_u32 , &server_config.max_leases , "235"}, 72 {"auto_time" , read_u32 , &server_config.auto_time , "7200"}, 73 {"decline_time" , read_u32 , &server_config.decline_time , "3600"}, 74 {"conflict_time", read_u32 , &server_config.conflict_time, "3600"}, 75 {"offer_time" , read_u32 , &server_config.offer_time , "60"}, 76 {"min_lease" , read_u32 , &server_config.min_lease_sec, "60"}, 77 {"lease_file" , read_str , &server_config.lease_file , LEASES_FILE}, 78 {"pidfile" , read_str , &server_config.pidfile , "/var/run/udhcpd.pid"}, 79 {"siaddr" , udhcp_str2nip , &server_config.siaddr_nip , "0.0.0.0"}, 80 /* keywords with no defaults must be last! */ 81 {"option" , udhcp_str2optset, &server_config.options , ""}, 82 {"opt" , udhcp_str2optset, &server_config.options , ""}, 83 {"notify_file" , read_str , &server_config.notify_file , ""}, 84 {"sname" , read_str , &server_config.sname , ""}, 85 {"boot_file" , read_str , &server_config.boot_file , ""}, 86 {"static_lease" , read_staticlease, &server_config.static_leases, ""}, 310 87 }; 311 312 313 /* 314 * Domain names may have 254 chars, and string options can be 254 315 * chars long. However, 80 bytes will be enough for most, and won't 316 * hog up memory. If you have a special application, change it 317 */ 318 #define READ_CONFIG_BUF_SIZE 80 319 320 int read_config(const char *file) 321 { 322 FILE *in; 323 char buffer[READ_CONFIG_BUF_SIZE], *token, *line; 324 int i, lm = 0; 325 326 for (i = 0; i < ARRAY_SIZE(keywords); i++) 327 if (keywords[i].def[0]) 328 keywords[i].handler(keywords[i].def, keywords[i].var); 329 330 in = fopen_or_warn(file, "r"); 331 if (!in) { 332 return 0; 333 } 334 335 while (fgets(buffer, READ_CONFIG_BUF_SIZE, in)) { 336 char debug_orig[READ_CONFIG_BUF_SIZE]; 337 char *p; 338 339 lm++; 340 p = strchr(buffer, '\n'); 341 if (p) *p = '\0'; 342 if (ENABLE_FEATURE_UDHCP_DEBUG) strcpy(debug_orig, buffer); 343 p = strchr(buffer, '#'); 344 if (p) *p = '\0'; 345 346 if (!(token = strtok(buffer, " \t"))) continue; 347 if (!(line = strtok(NULL, ""))) continue; 348 349 /* eat leading whitespace */ 350 line = skip_whitespace(line); 351 /* eat trailing whitespace */ 352 i = strlen(line) - 1; 353 while (i >= 0 && isspace(line[i])) 354 line[i--] = '\0'; 355 356 for (i = 0; i < ARRAY_SIZE(keywords); i++) 357 if (!strcasecmp(token, keywords[i].keyword)) 358 if (!keywords[i].handler(line, keywords[i].var)) { 359 bb_error_msg("cannot parse line %d of %s", lm, file); 360 if (ENABLE_FEATURE_UDHCP_DEBUG) 361 bb_error_msg("cannot parse '%s'", debug_orig); 88 enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 }; 89 90 void FAST_FUNC read_config(const char *file) 91 { 92 parser_t *parser; 93 const struct config_keyword *k; 94 unsigned i; 95 char *token[2]; 96 97 for (i = 0; i < KWS_WITH_DEFAULTS; i++) 98 keywords[i].handler(keywords[i].def, keywords[i].var); 99 100 parser = config_open(file); 101 while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) { 102 for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) { 103 if (strcasecmp(token[0], k->keyword) == 0) { 104 if (!k->handler(token[1], k->var)) { 105 bb_error_msg("can't parse line %u in %s", 106 parser->lineno, file); 362 107 /* reset back to the default value */ 363 k eywords[i].handler(keywords[i].def, keywords[i].var);108 k->handler(k->def, k->var); 364 109 } 365 } 366 fclose(in); 110 break; 111 } 112 } 113 } 114 config_close(parser); 367 115 368 116 server_config.start_ip = ntohl(server_config.start_ip); 369 117 server_config.end_ip = ntohl(server_config.end_ip); 370 371 return 1; 372 } 373 374 375 void write_leases(void) 376 { 377 int fp; 118 } 119 120 void FAST_FUNC write_leases(void) 121 { 122 int fd; 378 123 unsigned i; 379 time_t curr = time(0);380 unsigned long tmp_time;381 382 f p = open3_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC, 0666);383 if (f p < 0) {124 leasetime_t curr; 125 int64_t written_at; 126 127 fd = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC); 128 if (fd < 0) 384 129 return; 385 } 130 131 curr = written_at = time(NULL); 132 133 written_at = SWAP_BE64(written_at); 134 full_write(fd, &written_at, sizeof(written_at)); 386 135 387 136 for (i = 0; i < server_config.max_leases; i++) { 388 if (leases[i].yiaddr != 0) { 389 390 /* screw with the time in the struct, for easier writing */ 391 tmp_time = leases[i].expires; 392 393 if (server_config.remaining) { 394 if (lease_expired(&(leases[i]))) 395 leases[i].expires = 0; 396 else leases[i].expires -= curr; 397 } /* else stick with the time we got */ 398 leases[i].expires = htonl(leases[i].expires); 399 // FIXME: error check?? 400 full_write(fp, &leases[i], sizeof(leases[i])); 401 402 /* then restore it when done */ 403 leases[i].expires = tmp_time; 404 } 405 } 406 close(fp); 137 leasetime_t tmp_time; 138 139 if (g_leases[i].lease_nip == 0) 140 continue; 141 142 /* Screw with the time in the struct, for easier writing */ 143 tmp_time = g_leases[i].expires; 144 145 g_leases[i].expires -= curr; 146 if ((signed_leasetime_t) g_leases[i].expires < 0) 147 g_leases[i].expires = 0; 148 g_leases[i].expires = htonl(g_leases[i].expires); 149 150 /* No error check. If the file gets truncated, 151 * we lose some leases on restart. Oh well. */ 152 full_write(fd, &g_leases[i], sizeof(g_leases[i])); 153 154 /* Then restore it when done */ 155 g_leases[i].expires = tmp_time; 156 } 157 close(fd); 407 158 408 159 if (server_config.notify_file) { 409 char *cmd = xasprintf("%s %s", server_config.notify_file, server_config.lease_file); 410 system(cmd); 411 free(cmd); 412 } 413 } 414 415 416 void read_leases(const char *file) 417 { 418 int fp; 419 unsigned int i = 0; 420 struct dhcpOfferedAddr lease; 421 422 fp = open_or_warn(file, O_RDONLY); 423 if (fp < 0) { 160 char *argv[3]; 161 argv[0] = server_config.notify_file; 162 argv[1] = server_config.lease_file; 163 argv[2] = NULL; 164 spawn_and_wait(argv); 165 } 166 } 167 168 void FAST_FUNC read_leases(const char *file) 169 { 170 struct dyn_lease lease; 171 int64_t written_at, time_passed; 172 int fd; 173 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 174 unsigned i = 0; 175 #endif 176 177 fd = open_or_warn(file, O_RDONLY); 178 if (fd < 0) 424 179 return; 425 } 426 427 while (i < server_config.max_leases 428 && full_read(fp, &lease, sizeof(lease)) == sizeof(lease) 429 ) { 430 /* ADDME: is it a static lease */ 431 uint32_t y = ntohl(lease.yiaddr); 180 181 if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at)) 182 goto ret; 183 written_at = SWAP_BE64(written_at); 184 185 time_passed = time(NULL) - written_at; 186 /* Strange written_at, or lease file from old version of udhcpd 187 * which had no "written_at" field? */ 188 if ((uint64_t)time_passed > 12 * 60 * 60) 189 goto ret; 190 191 while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) { 192 //FIXME: what if it matches some static lease? 193 uint32_t y = ntohl(lease.lease_nip); 432 194 if (y >= server_config.start_ip && y <= server_config.end_ip) { 433 lease.expires = ntohl(lease.expires); 434 if (!server_config.remaining) 435 lease.expires -= time(0); 436 if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) { 195 signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed; 196 if (expires <= 0) 197 continue; 198 /* NB: add_lease takes "relative time", IOW, 199 * lease duration, not lease deadline. */ 200 if (add_lease(lease.lease_mac, lease.lease_nip, 201 expires, 202 lease.hostname, sizeof(lease.hostname) 203 ) == 0 204 ) { 437 205 bb_error_msg("too many leases while loading %s", file); 438 206 break; 439 207 } 208 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 440 209 i++; 210 #endif 441 211 } 442 212 } 443 DEBUG("Read %d leases", i); 444 close(fp); 445 } 213 log1("Read %d leases", i); 214 ret: 215 close(fd); 216 }
Note:
See TracChangeset
for help on using the changeset viewer.