📄 options.c
字号:
struct dhcp_packet *outpacket; struct lease *lease; struct client_state *client_state; int mms; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; int overload; /* Overload flags that may be set. */ int terminate; int bootpp; struct data_string *prl; const char *vuname;{#define PRIORITY_COUNT 300 unsigned priority_list [PRIORITY_COUNT]; int priority_len; unsigned char buffer [4096]; /* Really big buffer... */ unsigned main_buffer_size; unsigned mainbufix, bufix, agentix; unsigned option_size; unsigned length; int i; struct option_cache *op; struct data_string ds; pair pp, *hash; int need_endopt = 0; int have_sso = 0; memset (&ds, 0, sizeof ds); /* If there's a Maximum Message Size option in the incoming packet and no alternate maximum message size has been specified, take the one in the packet. */ if (inpacket && (op = lookup_option (&dhcp_universe, inpacket -> options, DHO_DHCP_MAX_MESSAGE_SIZE))) { evaluate_option_cache (&ds, inpacket, lease, client_state, in_options, cfg_options, scope, op, MDL); if (ds.len >= sizeof (u_int16_t)) { i = getUShort (ds.data); if(!mms || (i < mms)) mms = i; } data_string_forget (&ds, MDL); } /* If the client has provided a maximum DHCP message size, use that; otherwise, if it's BOOTP, only 64 bytes; otherwise use up to the minimum IP MTU size (576 bytes). */ /* XXX if a BOOTP client specifies a max message size, we will honor it. */ if (mms) { main_buffer_size = mms - DHCP_FIXED_LEN; /* Enforce a minimum packet size... */ if (main_buffer_size < (576 - DHCP_FIXED_LEN)) main_buffer_size = 576 - DHCP_FIXED_LEN; } else if (bootpp) { if (inpacket) { main_buffer_size = inpacket -> packet_length - DHCP_FIXED_LEN; if (main_buffer_size < 64) main_buffer_size = 64; } else main_buffer_size = 64; } else main_buffer_size = 576 - DHCP_FIXED_LEN; /* Set a hard limit at the size of the output buffer. */ if (main_buffer_size > sizeof buffer) main_buffer_size = sizeof buffer; /* Preload the option priority list with mandatory options. */ priority_len = 0; priority_list [priority_len++] = DHO_DHCP_MESSAGE_TYPE; priority_list [priority_len++] = DHO_DHCP_SERVER_IDENTIFIER; priority_list [priority_len++] = DHO_DHCP_LEASE_TIME; priority_list [priority_len++] = DHO_DHCP_MESSAGE; priority_list [priority_len++] = DHO_DHCP_REQUESTED_ADDRESS; priority_list [priority_len++] = DHO_FQDN; if (prl && prl -> len > 0) { if ((op = lookup_option (&dhcp_universe, cfg_options, DHO_SUBNET_SELECTION))) { if (priority_len < PRIORITY_COUNT) priority_list [priority_len++] = DHO_SUBNET_SELECTION; } data_string_truncate (prl, (PRIORITY_COUNT - priority_len)); for (i = 0; i < prl -> len; i++) { /* Prevent client from changing order of delivery of relay agent information option. */ if (prl -> data [i] != DHO_DHCP_AGENT_OPTIONS) priority_list [priority_len++] = prl -> data [i]; } } else { /* First, hardcode some more options that ought to be sent first... */ priority_list [priority_len++] = DHO_SUBNET_MASK; priority_list [priority_len++] = DHO_ROUTERS; priority_list [priority_len++] = DHO_DOMAIN_NAME_SERVERS; priority_list [priority_len++] = DHO_HOST_NAME; /* Append a list of the standard DHCP options from the standard DHCP option space. Actually, if a site option space hasn't been specified, we wind up treating the dhcp option space as the site option space, and the first for loop is skipped, because it's slightly more general to do it this way, taking the 1Q99 DHCP futures work into account. */ if (cfg_options -> site_code_min) { for (i = 0; i < OPTION_HASH_SIZE; i++) { hash = cfg_options -> universes [dhcp_universe.index]; if (hash) { for (pp = hash [i]; pp; pp = pp -> cdr) { op = (struct option_cache *)(pp -> car); if (op -> option -> code < cfg_options -> site_code_min && priority_len < PRIORITY_COUNT && (op -> option -> code != DHO_DHCP_AGENT_OPTIONS)) priority_list [priority_len++] = op -> option -> code; } } } } /* Now cycle through the site option space, or if there is no site option space, we'll be cycling through the dhcp option space. */ for (i = 0; i < OPTION_HASH_SIZE; i++) { hash = (cfg_options -> universes [cfg_options -> site_universe]); if (hash) for (pp = hash [i]; pp; pp = pp -> cdr) { op = (struct option_cache *)(pp -> car); if (op -> option -> code >= cfg_options -> site_code_min && priority_len < PRIORITY_COUNT && (op -> option -> code != DHO_DHCP_AGENT_OPTIONS)) priority_list [priority_len++] = op -> option -> code; } } /* Now go through all the universes for which options were set and see if there are encapsulations for them; if there are, put the encapsulation options on the priority list as well. */ for (i = 0; i < cfg_options -> universe_count; i++) { if (cfg_options -> universes [i] && universes [i] -> enc_opt && priority_len < PRIORITY_COUNT && universes [i] -> enc_opt -> universe == &dhcp_universe) { if (universes [i] -> enc_opt -> code != DHO_DHCP_AGENT_OPTIONS) priority_list [priority_len++] = universes [i] -> enc_opt -> code; } } /* The vendor option space can't stand on its own, so always add it to the list. */ if (priority_len < PRIORITY_COUNT) priority_list [priority_len++] = DHO_VENDOR_ENCAPSULATED_OPTIONS; } /* Copy the options into the big buffer... */ option_size = store_options (buffer, (main_buffer_size - 7 + ((overload & 1) ? DHCP_FILE_LEN : 0) + ((overload & 2) ? DHCP_SNAME_LEN : 0)), inpacket, lease, client_state, in_options, cfg_options, scope, priority_list, priority_len, main_buffer_size, (main_buffer_size + ((overload & 1) ? DHCP_FILE_LEN : 0)), terminate, vuname); /* Put the cookie up front... */ memcpy (outpacket -> options, DHCP_OPTIONS_COOKIE, 4); mainbufix = 4; /* If we're going to have to overload, store the overload option at the beginning. If we can, though, just store the whole thing in the packet's option buffer and leave it at that. */ if (option_size <= main_buffer_size - mainbufix) { memcpy (&outpacket -> options [mainbufix], buffer, option_size); mainbufix += option_size; agentix = mainbufix; if (mainbufix < main_buffer_size) need_endopt = 1; length = DHCP_FIXED_NON_UDP + mainbufix; } else { outpacket -> options [mainbufix++] = DHO_DHCP_OPTION_OVERLOAD; outpacket -> options [mainbufix++] = 1; if (option_size > main_buffer_size - mainbufix + DHCP_FILE_LEN) outpacket -> options [mainbufix++] = 3; else outpacket -> options [mainbufix++] = 1; memcpy (&outpacket -> options [mainbufix], buffer, main_buffer_size - mainbufix); length = DHCP_FIXED_NON_UDP + main_buffer_size; agentix = main_buffer_size; bufix = main_buffer_size - mainbufix; if (overload & 1) { if (option_size - bufix <= DHCP_FILE_LEN) { memcpy (outpacket -> file, &buffer [bufix], option_size - bufix); mainbufix = option_size - bufix; if (mainbufix < DHCP_FILE_LEN) outpacket -> file [mainbufix++] = DHO_END; while (mainbufix < DHCP_FILE_LEN) outpacket -> file [mainbufix++] = DHO_PAD; } else { memcpy (outpacket -> file, &buffer [bufix], DHCP_FILE_LEN); bufix += DHCP_FILE_LEN; } } if ((overload & 2) && option_size < bufix) { memcpy (outpacket -> sname, &buffer [bufix], option_size - bufix); mainbufix = option_size - bufix; if (mainbufix < DHCP_SNAME_LEN) outpacket -> file [mainbufix++] = DHO_END; while (mainbufix < DHCP_SNAME_LEN) outpacket -> file [mainbufix++] = DHO_PAD; } } /* Now hack in the agent options if there are any. */ priority_list [0] = DHO_DHCP_AGENT_OPTIONS; priority_len = 1; agentix += store_options (&outpacket -> options [agentix], 1500 - DHCP_FIXED_LEN - agentix, inpacket, lease, client_state, in_options, cfg_options, scope, priority_list, priority_len, 1500 - DHCP_FIXED_LEN - agentix, 1500 - DHCP_FIXED_LEN - agentix, 0, (char *)0); /* Tack a DHO_END option onto the packet if we need to. */ if (agentix < 1500 - DHCP_FIXED_LEN && need_endopt) outpacket -> options [agentix++] = DHO_END; /* Figure out the length. */ length = DHCP_FIXED_NON_UDP + agentix; return length;}/* Store all the requested options into the requested buffer. */int store_options (buffer, buflen, packet, lease, client_state, in_options, cfg_options, scope, priority_list, priority_len, first_cutoff, second_cutoff, terminate, vuname) unsigned char *buffer; unsigned buflen; struct packet *packet; struct lease *lease; struct client_state *client_state; struct option_state *in_options; struct option_state *cfg_options; struct binding_scope **scope; unsigned *priority_list; int priority_len; unsigned first_cutoff, second_cutoff; int terminate; const char *vuname;{ int bufix = 0; int i; int ix; int tto; struct data_string od; struct option_cache *oc; unsigned code; int optstart; memset (&od, 0, sizeof od); /* Eliminate duplicate options in the parameter request list. There's got to be some clever knuthian way to do this: Eliminate all but the first occurance of a value in an array of values without otherwise disturbing the order of the array. */ for (i = 0; i < priority_len - 1; i++) { tto = 0; for (ix = i + 1; ix < priority_len + tto; ix++) { if (tto) priority_list [ix - tto] = priority_list [ix]; if (priority_list [i] == priority_list [ix]) { tto++; priority_len--; } } } /* Copy out the options in the order that they appear in the priority list... */ for (i = 0; i < priority_len; i++) { /* Number of bytes left to store (some may already have been stored by a previous pass). */ unsigned length; int optstart; struct universe *u; int have_encapsulation = 0; struct data_string encapsulation; memset (&encapsulation, 0, sizeof encapsulation); /* Code for next option to try to store. */ code = priority_list [i]; /* Look up the option in the site option space if the code is above the cutoff, otherwise in the DHCP option space. */ if (code >= cfg_options -> site_code_min) u = universes [cfg_options -> site_universe]; else u = &dhcp_universe; oc = lookup_option (u, cfg_options, code); /* It's an encapsulation, try to find the universe to be encapsulated first, except that if it's a straight encapsulation and the user has provided a value for the encapsulation option, use the user-provided value. */ if (u -> options [code] && ((u -> options [code] -> format [0] == 'E' && !oc) || u -> options [code] -> format [0] == 'e')) { int uix; static char *s, *t; struct option_cache *tmp; struct data_string name; s = strchr (u -> options [code] -> format, 'E'); if (s) t = strchr (++s, '.'); if (s && t) { memset (&name, 0, sizeof name); /* A zero-length universe name means the vendor option space, if one is defined. */ if (t == s) { if (vendor_cfg_option) { tmp = lookup_option (vendor_cfg_option -> universe, cfg_options, vendor_cfg_option -> code); if (tmp) evaluate_option_cache (&name, packet, lease, client_state, in_options, cfg_options, scope, tmp, MDL); } else if (vuname) { name.data = (unsigned char *)s; name.len = strlen (s); } } else { name.data = (unsigned char *)s; name.len = t - s; } /* If we found a universe, and there are options configured for that universe, try to encapsulate it. */ if (name.len) { have_encapsulation = (option_space_encapsulate (&encapsulation, packet, lease, client_state, in_options, cfg_options, scope, &name)); data_string_forget (&name, MDL); } } } /* In order to avoid memory leaks, we have to get to here with any option cache that we allocated in tmp not being referenced by tmp, and whatever option cache is referenced by oc being an actual reference. lookup_option doesn't generate a reference (this needs to be fixed), so the preceding goop ensures that if we *didn't* generate a new option cache, oc still winds up holding an actual reference. */ /* If no data is available for this option, skip it. */ if (!oc && !have_encapsulation) { continue; } /* Find the value of the option... */ if (oc) { evaluate_option_cache (&od, packet, lease, client_state, in_options, cfg_options, scope, oc, MDL); if (!od.len) { data_string_forget (&encapsulation, MDL); data_string_forget (&od, MDL); have_encapsulation = 0; continue; } } /* We should now have a constant length for the option. */ length = od.len; if (have_encapsulation) { length += encapsulation.len; if (!od.len) { data_string_copy (&od, &encapsulation, MDL); data_string_forget (&encapsulation, MDL); } else { struct buffer *bp = (struct buffer *)0; if (!buffer_allocate (&bp, length, MDL)) { option_cache_dereference (&oc, MDL); data_string_forget (&od, MDL); data_string_forget (&encapsulation, MDL); continue; } memcpy (&bp -> data [0], od.data, od.len); memcpy (&bp -> data [od.len], encapsulation.data, encapsulation.len); data_string_forget (&od, MDL); data_string_forget (&encapsulation, MDL); od.data = &bp -> data [0]; buffer_reference (&od.buffer, bp, MDL); buffer_dereference (&bp, MDL); od.len = length; od.terminated = 0; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -