1*6562b533Skrw /* $OpenBSD: options.c,v 1.121 2020/05/14 13:57:13 krw Exp $ */ 29a2590e5Sderaadt 3e7eb2effShenning /* DHCP options parsing and reassembly. */ 49a2590e5Sderaadt 59a2590e5Sderaadt /* 69a2590e5Sderaadt * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. 79a2590e5Sderaadt * All rights reserved. 89a2590e5Sderaadt * 99a2590e5Sderaadt * Redistribution and use in source and binary forms, with or without 109a2590e5Sderaadt * modification, are permitted provided that the following conditions 119a2590e5Sderaadt * are met: 129a2590e5Sderaadt * 139a2590e5Sderaadt * 1. Redistributions of source code must retain the above copyright 149a2590e5Sderaadt * notice, this list of conditions and the following disclaimer. 159a2590e5Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 169a2590e5Sderaadt * notice, this list of conditions and the following disclaimer in the 179a2590e5Sderaadt * documentation and/or other materials provided with the distribution. 189a2590e5Sderaadt * 3. Neither the name of The Internet Software Consortium nor the names 199a2590e5Sderaadt * of its contributors may be used to endorse or promote products derived 209a2590e5Sderaadt * from this software without specific prior written permission. 219a2590e5Sderaadt * 229a2590e5Sderaadt * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 239a2590e5Sderaadt * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 249a2590e5Sderaadt * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 259a2590e5Sderaadt * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 269a2590e5Sderaadt * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 279a2590e5Sderaadt * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 289a2590e5Sderaadt * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 299a2590e5Sderaadt * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 309a2590e5Sderaadt * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 319a2590e5Sderaadt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 329a2590e5Sderaadt * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 339a2590e5Sderaadt * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 349a2590e5Sderaadt * SUCH DAMAGE. 359a2590e5Sderaadt * 369a2590e5Sderaadt * This software has been written for the Internet Software Consortium 379a2590e5Sderaadt * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 389a2590e5Sderaadt * Enterprises. To learn more about the Internet Software Consortium, 399a2590e5Sderaadt * see ``http://www.vix.com/isc''. To learn more about Vixie 409a2590e5Sderaadt * Enterprises, see ``http://www.vix.com''. 419a2590e5Sderaadt */ 429a2590e5Sderaadt 43711cae1eSkrw #include <sys/queue.h> 44711cae1eSkrw #include <sys/socket.h> 459a2590e5Sderaadt 46711cae1eSkrw #include <arpa/inet.h> 47711cae1eSkrw 48711cae1eSkrw #include <net/if.h> 49711cae1eSkrw 50711cae1eSkrw #include <netinet/in.h> 51711cae1eSkrw #include <netinet/if_ether.h> 52711cae1eSkrw 53711cae1eSkrw #include <ctype.h> 54f1e54185Skrw #include <resolv.h> 55711cae1eSkrw #include <signal.h> 56711cae1eSkrw #include <stdio.h> 57711cae1eSkrw #include <stdlib.h> 58711cae1eSkrw #include <string.h> 598d2bd14bSkrw #include <vis.h> 608d2bd14bSkrw 61711cae1eSkrw #include "dhcp.h" 62711cae1eSkrw #include "dhcpd.h" 63385a6373Skrw #include "log.h" 64711cae1eSkrw 6502e02bd5Skrw int parse_option_buffer(struct option_data *, unsigned char *, int); 661abdd88fSkrw void pretty_print_classless_routes(unsigned char *, size_t, unsigned char *, 671abdd88fSkrw size_t); 68f1e54185Skrw void pretty_print_domain_list(unsigned char *, size_t, unsigned char *, 69f1e54185Skrw size_t); 709a2590e5Sderaadt 71c714dadcShenning /* 728457ebc2Skrw * DHCP Option names, formats and codes, from RFC1533. 738457ebc2Skrw * 748457ebc2Skrw * Format codes: 758457ebc2Skrw * 768457ebc2Skrw * e - end of data 778457ebc2Skrw * I - IP address 788457ebc2Skrw * l - 32-bit signed integer 798457ebc2Skrw * L - 32-bit unsigned integer 808457ebc2Skrw * S - 16-bit unsigned integer 818457ebc2Skrw * B - 8-bit unsigned integer 828457ebc2Skrw * t - ASCII text 838457ebc2Skrw * f - flag (true or false) 848457ebc2Skrw * A - array of whatever precedes (e.g., IA means array of IP addresses) 858457ebc2Skrw * C - CIDR description 86d712a45dSkrw * X - hex octets 87f1e54185Skrw * D - domain name list, comma separated list of domain names. 888457ebc2Skrw */ 898457ebc2Skrw 908457ebc2Skrw static const struct { 918457ebc2Skrw char *name; 928457ebc2Skrw char *format; 938457ebc2Skrw } dhcp_options[DHO_COUNT] = { 948457ebc2Skrw /* 0 */ { "pad", "" }, 958457ebc2Skrw /* 1 */ { "subnet-mask", "I" }, 968457ebc2Skrw /* 2 */ { "time-offset", "l" }, 978457ebc2Skrw /* 3 */ { "routers", "IA" }, 988457ebc2Skrw /* 4 */ { "time-servers", "IA" }, 998457ebc2Skrw /* 5 */ { "ien116-name-servers", "IA" }, 1008457ebc2Skrw /* 6 */ { "domain-name-servers", "IA" }, 1018457ebc2Skrw /* 7 */ { "log-servers", "IA" }, 1028457ebc2Skrw /* 8 */ { "cookie-servers", "IA" }, 1038457ebc2Skrw /* 9 */ { "lpr-servers", "IA" }, 1048457ebc2Skrw /* 10 */ { "impress-servers", "IA" }, 1058457ebc2Skrw /* 11 */ { "resource-location-servers", "IA" }, 1068457ebc2Skrw /* 12 */ { "host-name", "t" }, 1078457ebc2Skrw /* 13 */ { "boot-size", "S" }, 1088457ebc2Skrw /* 14 */ { "merit-dump", "t" }, 1098457ebc2Skrw /* 15 */ { "domain-name", "t" }, 1108457ebc2Skrw /* 16 */ { "swap-server", "I" }, 1118457ebc2Skrw /* 17 */ { "root-path", "t" }, 1128457ebc2Skrw /* 18 */ { "extensions-path", "t" }, 1138457ebc2Skrw /* 19 */ { "ip-forwarding", "f" }, 1148457ebc2Skrw /* 20 */ { "non-local-source-routing", "f" }, 1158457ebc2Skrw /* 21 */ { "policy-filter", "IIA" }, 1168457ebc2Skrw /* 22 */ { "max-dgram-reassembly", "S" }, 1178457ebc2Skrw /* 23 */ { "default-ip-ttl", "B" }, 1188457ebc2Skrw /* 24 */ { "path-mtu-aging-timeout", "L" }, 1198457ebc2Skrw /* 25 */ { "path-mtu-plateau-table", "SA" }, 1208457ebc2Skrw /* 26 */ { "interface-mtu", "S" }, 1218457ebc2Skrw /* 27 */ { "all-subnets-local", "f" }, 1228457ebc2Skrw /* 28 */ { "broadcast-address", "I" }, 1238457ebc2Skrw /* 29 */ { "perform-mask-discovery", "f" }, 1248457ebc2Skrw /* 30 */ { "mask-supplier", "f" }, 1258457ebc2Skrw /* 31 */ { "router-discovery", "f" }, 1268457ebc2Skrw /* 32 */ { "router-solicitation-address", "I" }, 1278457ebc2Skrw /* 33 */ { "static-routes", "IIA" }, 1288457ebc2Skrw /* 34 */ { "trailer-encapsulation", "f" }, 1298457ebc2Skrw /* 35 */ { "arp-cache-timeout", "L" }, 1308457ebc2Skrw /* 36 */ { "ieee802-3-encapsulation", "f" }, 1318457ebc2Skrw /* 37 */ { "default-tcp-ttl", "B" }, 1328457ebc2Skrw /* 38 */ { "tcp-keepalive-interval", "L" }, 1338457ebc2Skrw /* 39 */ { "tcp-keepalive-garbage", "f" }, 1348457ebc2Skrw /* 40 */ { "nis-domain", "t" }, 1358457ebc2Skrw /* 41 */ { "nis-servers", "IA" }, 1368457ebc2Skrw /* 42 */ { "ntp-servers", "IA" }, 1378457ebc2Skrw /* 43 */ { "vendor-encapsulated-options", "X" }, 1388457ebc2Skrw /* 44 */ { "netbios-name-servers", "IA" }, 1398457ebc2Skrw /* 45 */ { "netbios-dd-server", "IA" }, 1408457ebc2Skrw /* 46 */ { "netbios-node-type", "B" }, 1418457ebc2Skrw /* 47 */ { "netbios-scope", "t" }, 1428457ebc2Skrw /* 48 */ { "font-servers", "IA" }, 1438457ebc2Skrw /* 49 */ { "x-display-manager", "IA" }, 1448457ebc2Skrw /* 50 */ { "dhcp-requested-address", "I" }, 1458457ebc2Skrw /* 51 */ { "dhcp-lease-time", "L" }, 1468457ebc2Skrw /* 52 */ { "dhcp-option-overload", "B" }, 1478457ebc2Skrw /* 53 */ { "dhcp-message-type", "B" }, 1488457ebc2Skrw /* 54 */ { "dhcp-server-identifier", "I" }, 1498457ebc2Skrw /* 55 */ { "dhcp-parameter-request-list", "BA" }, 1508457ebc2Skrw /* 56 */ { "dhcp-message", "t" }, 1518457ebc2Skrw /* 57 */ { "dhcp-max-message-size", "S" }, 1528457ebc2Skrw /* 58 */ { "dhcp-renewal-time", "L" }, 1538457ebc2Skrw /* 59 */ { "dhcp-rebinding-time", "L" }, 1548457ebc2Skrw /* 60 */ { "dhcp-class-identifier", "t" }, 1558457ebc2Skrw /* 61 */ { "dhcp-client-identifier", "X" }, 1568457ebc2Skrw /* 62 */ { NULL, NULL }, 1578457ebc2Skrw /* 63 */ { NULL, NULL }, 1588457ebc2Skrw /* 64 */ { "nisplus-domain", "t" }, 1598457ebc2Skrw /* 65 */ { "nisplus-servers", "IA" }, 1608457ebc2Skrw /* 66 */ { "tftp-server-name", "t" }, 1618457ebc2Skrw /* 67 */ { "bootfile-name", "t" }, 1628457ebc2Skrw /* 68 */ { "mobile-ip-home-agent", "IA" }, 1638457ebc2Skrw /* 69 */ { "smtp-server", "IA" }, 1648457ebc2Skrw /* 70 */ { "pop-server", "IA" }, 1658457ebc2Skrw /* 71 */ { "nntp-server", "IA" }, 1668457ebc2Skrw /* 72 */ { "www-server", "IA" }, 1678457ebc2Skrw /* 73 */ { "finger-server", "IA" }, 1688457ebc2Skrw /* 74 */ { "irc-server", "IA" }, 1698457ebc2Skrw /* 75 */ { "streettalk-server", "IA" }, 1708457ebc2Skrw /* 76 */ { "streettalk-directory-assistance-server", "IA" }, 1718457ebc2Skrw /* 77 */ { "user-class", "t" }, 1728457ebc2Skrw /* 78 */ { NULL, NULL }, 1738457ebc2Skrw /* 79 */ { NULL, NULL }, 1748457ebc2Skrw /* 80 */ { NULL, NULL }, 1758457ebc2Skrw /* 81 */ { NULL, NULL }, 1768457ebc2Skrw /* 82 */ { "relay-agent-information", "X" }, 1778457ebc2Skrw /* 83 */ { NULL, NULL }, 1788457ebc2Skrw /* 84 */ { NULL, NULL }, 1798457ebc2Skrw /* 85 */ { "nds-servers", "IA" }, 1808457ebc2Skrw /* 86 */ { "nds-tree-name", "X" }, 1818457ebc2Skrw /* 87 */ { "nds-context", "X" }, 1828457ebc2Skrw /* 88 */ { NULL, NULL }, 1838457ebc2Skrw /* 89 */ { NULL, NULL }, 1848457ebc2Skrw /* 90 */ { NULL, NULL }, 1858457ebc2Skrw /* 91 */ { NULL, NULL }, 1868457ebc2Skrw /* 92 */ { NULL, NULL }, 1878457ebc2Skrw /* 93 */ { NULL, NULL }, 1888457ebc2Skrw /* 94 */ { NULL, NULL }, 1898457ebc2Skrw /* 95 */ { NULL, NULL }, 1908457ebc2Skrw /* 96 */ { NULL, NULL }, 1918457ebc2Skrw /* 97 */ { NULL, NULL }, 1928457ebc2Skrw /* 98 */ { NULL, NULL }, 1938457ebc2Skrw /* 99 */ { NULL, NULL }, 1948457ebc2Skrw /* 100 */ { NULL, NULL }, 1958457ebc2Skrw /* 101 */ { NULL, NULL }, 1968457ebc2Skrw /* 102 */ { NULL, NULL }, 1978457ebc2Skrw /* 103 */ { NULL, NULL }, 1988457ebc2Skrw /* 104 */ { NULL, NULL }, 1998457ebc2Skrw /* 105 */ { NULL, NULL }, 2008457ebc2Skrw /* 106 */ { NULL, NULL }, 2018457ebc2Skrw /* 107 */ { NULL, NULL }, 2028457ebc2Skrw /* 108 */ { NULL, NULL }, 2038457ebc2Skrw /* 109 */ { NULL, NULL }, 2048457ebc2Skrw /* 110 */ { NULL, NULL }, 2058457ebc2Skrw /* 111 */ { NULL, NULL }, 2068457ebc2Skrw /* 112 */ { NULL, NULL }, 2078457ebc2Skrw /* 113 */ { NULL, NULL }, 2088457ebc2Skrw /* 114 */ { NULL, NULL }, 2098457ebc2Skrw /* 115 */ { NULL, NULL }, 2108457ebc2Skrw /* 116 */ { NULL, NULL }, 2118457ebc2Skrw /* 117 */ { NULL, NULL }, 2128457ebc2Skrw /* 118 */ { NULL, NULL }, 213f1e54185Skrw /* 119 */ { "domain-search", "D" }, 2148457ebc2Skrw /* 120 */ { NULL, NULL }, 2158457ebc2Skrw /* 121 */ { "classless-static-routes", "CIA" }, 2168457ebc2Skrw /* 122 */ { NULL, NULL }, 2178457ebc2Skrw /* 123 */ { NULL, NULL }, 2188457ebc2Skrw /* 124 */ { NULL, NULL }, 2198457ebc2Skrw /* 125 */ { NULL, NULL }, 2208457ebc2Skrw /* 126 */ { NULL, NULL }, 2218457ebc2Skrw /* 127 */ { NULL, NULL }, 2228457ebc2Skrw /* 128 */ { NULL, NULL }, 2238457ebc2Skrw /* 129 */ { NULL, NULL }, 2248457ebc2Skrw /* 130 */ { NULL, NULL }, 2258457ebc2Skrw /* 131 */ { NULL, NULL }, 2268457ebc2Skrw /* 132 */ { NULL, NULL }, 2278457ebc2Skrw /* 133 */ { NULL, NULL }, 2288457ebc2Skrw /* 134 */ { NULL, NULL }, 2298457ebc2Skrw /* 135 */ { NULL, NULL }, 2308457ebc2Skrw /* 136 */ { NULL, NULL }, 2318457ebc2Skrw /* 137 */ { NULL, NULL }, 2328457ebc2Skrw /* 138 */ { NULL, NULL }, 2338457ebc2Skrw /* 139 */ { NULL, NULL }, 2348457ebc2Skrw /* 140 */ { NULL, NULL }, 2358457ebc2Skrw /* 141 */ { NULL, NULL }, 2368457ebc2Skrw /* 142 */ { NULL, NULL }, 2378457ebc2Skrw /* 143 */ { NULL, NULL }, 2388457ebc2Skrw /* 144 */ { "tftp-config-file", "t" }, 2398457ebc2Skrw /* 145 */ { NULL, NULL }, 2408457ebc2Skrw /* 146 */ { NULL, NULL }, 2418457ebc2Skrw /* 147 */ { NULL, NULL }, 2428457ebc2Skrw /* 148 */ { NULL, NULL }, 2438457ebc2Skrw /* 149 */ { NULL, NULL }, 2448457ebc2Skrw /* 150 */ { "voip-configuration-server", "IA" }, 2458457ebc2Skrw /* 151 */ { NULL, NULL }, 2468457ebc2Skrw /* 152 */ { NULL, NULL }, 2478457ebc2Skrw /* 153 */ { NULL, NULL }, 2488457ebc2Skrw /* 154 */ { NULL, NULL }, 2498457ebc2Skrw /* 155 */ { NULL, NULL }, 2508457ebc2Skrw /* 156 */ { NULL, NULL }, 2518457ebc2Skrw /* 157 */ { NULL, NULL }, 2528457ebc2Skrw /* 158 */ { NULL, NULL }, 2538457ebc2Skrw /* 159 */ { NULL, NULL }, 2548457ebc2Skrw /* 160 */ { NULL, NULL }, 2558457ebc2Skrw /* 161 */ { NULL, NULL }, 2568457ebc2Skrw /* 162 */ { NULL, NULL }, 2578457ebc2Skrw /* 163 */ { NULL, NULL }, 2588457ebc2Skrw /* 164 */ { NULL, NULL }, 2598457ebc2Skrw /* 165 */ { NULL, NULL }, 2608457ebc2Skrw /* 166 */ { NULL, NULL }, 2618457ebc2Skrw /* 167 */ { NULL, NULL }, 2628457ebc2Skrw /* 168 */ { NULL, NULL }, 2638457ebc2Skrw /* 169 */ { NULL, NULL }, 2648457ebc2Skrw /* 170 */ { NULL, NULL }, 2658457ebc2Skrw /* 171 */ { NULL, NULL }, 2668457ebc2Skrw /* 172 */ { NULL, NULL }, 2678457ebc2Skrw /* 173 */ { NULL, NULL }, 2688457ebc2Skrw /* 174 */ { NULL, NULL }, 2698457ebc2Skrw /* 175 */ { NULL, NULL }, 2708457ebc2Skrw /* 176 */ { NULL, NULL }, 2718457ebc2Skrw /* 177 */ { NULL, NULL }, 2728457ebc2Skrw /* 178 */ { NULL, NULL }, 2738457ebc2Skrw /* 179 */ { NULL, NULL }, 2748457ebc2Skrw /* 180 */ { NULL, NULL }, 2758457ebc2Skrw /* 181 */ { NULL, NULL }, 2768457ebc2Skrw /* 182 */ { NULL, NULL }, 2778457ebc2Skrw /* 183 */ { NULL, NULL }, 2788457ebc2Skrw /* 184 */ { NULL, NULL }, 2798457ebc2Skrw /* 185 */ { NULL, NULL }, 2808457ebc2Skrw /* 186 */ { NULL, NULL }, 2818457ebc2Skrw /* 187 */ { NULL, NULL }, 2828457ebc2Skrw /* 188 */ { NULL, NULL }, 2838457ebc2Skrw /* 189 */ { NULL, NULL }, 2848457ebc2Skrw /* 190 */ { NULL, NULL }, 2858457ebc2Skrw /* 191 */ { NULL, NULL }, 2868457ebc2Skrw /* 192 */ { NULL, NULL }, 2878457ebc2Skrw /* 193 */ { NULL, NULL }, 2888457ebc2Skrw /* 194 */ { NULL, NULL }, 2898457ebc2Skrw /* 195 */ { NULL, NULL }, 2908457ebc2Skrw /* 196 */ { NULL, NULL }, 2918457ebc2Skrw /* 197 */ { NULL, NULL }, 2928457ebc2Skrw /* 198 */ { NULL, NULL }, 2938457ebc2Skrw /* 199 */ { NULL, NULL }, 2948457ebc2Skrw /* 200 */ { NULL, NULL }, 2958457ebc2Skrw /* 201 */ { NULL, NULL }, 2968457ebc2Skrw /* 202 */ { NULL, NULL }, 2978457ebc2Skrw /* 203 */ { NULL, NULL }, 2988457ebc2Skrw /* 204 */ { NULL, NULL }, 2998457ebc2Skrw /* 205 */ { NULL, NULL }, 3008457ebc2Skrw /* 206 */ { NULL, NULL }, 3018457ebc2Skrw /* 207 */ { NULL, NULL }, 3028457ebc2Skrw /* 208 */ { NULL, NULL }, 3038457ebc2Skrw /* 209 */ { NULL, NULL }, 3048457ebc2Skrw /* 210 */ { NULL, NULL }, 3058457ebc2Skrw /* 211 */ { NULL, NULL }, 3068457ebc2Skrw /* 212 */ { NULL, NULL }, 3078457ebc2Skrw /* 213 */ { NULL, NULL }, 3088457ebc2Skrw /* 214 */ { NULL, NULL }, 3098457ebc2Skrw /* 215 */ { NULL, NULL }, 3108457ebc2Skrw /* 216 */ { NULL, NULL }, 3118457ebc2Skrw /* 217 */ { NULL, NULL }, 3128457ebc2Skrw /* 218 */ { NULL, NULL }, 3138457ebc2Skrw /* 219 */ { NULL, NULL }, 3148457ebc2Skrw /* 220 */ { NULL, NULL }, 3158457ebc2Skrw /* 221 */ { NULL, NULL }, 3168457ebc2Skrw /* 222 */ { NULL, NULL }, 3178457ebc2Skrw /* 223 */ { NULL, NULL }, 3188457ebc2Skrw /* 224 */ { NULL, NULL }, 3198457ebc2Skrw /* 225 */ { NULL, NULL }, 3208457ebc2Skrw /* 226 */ { NULL, NULL }, 3218457ebc2Skrw /* 227 */ { NULL, NULL }, 3228457ebc2Skrw /* 228 */ { NULL, NULL }, 3238457ebc2Skrw /* 229 */ { NULL, NULL }, 3248457ebc2Skrw /* 230 */ { NULL, NULL }, 3258457ebc2Skrw /* 231 */ { NULL, NULL }, 3268457ebc2Skrw /* 232 */ { NULL, NULL }, 3278457ebc2Skrw /* 233 */ { NULL, NULL }, 3288457ebc2Skrw /* 234 */ { NULL, NULL }, 3298457ebc2Skrw /* 235 */ { NULL, NULL }, 3308457ebc2Skrw /* 236 */ { NULL, NULL }, 3318457ebc2Skrw /* 237 */ { NULL, NULL }, 3328457ebc2Skrw /* 238 */ { NULL, NULL }, 3338457ebc2Skrw /* 239 */ { NULL, NULL }, 3348457ebc2Skrw /* 240 */ { NULL, NULL }, 3358457ebc2Skrw /* 241 */ { NULL, NULL }, 3368457ebc2Skrw /* 242 */ { NULL, NULL }, 3378457ebc2Skrw /* 243 */ { NULL, NULL }, 3388457ebc2Skrw /* 244 */ { NULL, NULL }, 3398457ebc2Skrw /* 245 */ { NULL, NULL }, 3408457ebc2Skrw /* 246 */ { NULL, NULL }, 3418457ebc2Skrw /* 247 */ { NULL, NULL }, 3428457ebc2Skrw /* 248 */ { NULL, NULL }, 3438457ebc2Skrw /* 249 */ { "classless-ms-static-routes", "CIA" }, 3448457ebc2Skrw /* 250 */ { NULL, NULL }, 3458457ebc2Skrw /* 251 */ { NULL, NULL }, 3468457ebc2Skrw /* 252 */ { "autoproxy-script", "t" }, 3478457ebc2Skrw /* 253 */ { NULL, NULL }, 3488457ebc2Skrw /* 254 */ { NULL, NULL }, 3498457ebc2Skrw /* 255 */ { "option-end", "e" }, 3508457ebc2Skrw }; 3518457ebc2Skrw 3528457ebc2Skrw char * 3538457ebc2Skrw code_to_name(int code) 3548457ebc2Skrw { 3558457ebc2Skrw static char unknown[11]; /* "option-NNN" */ 3568457ebc2Skrw int ret; 3578457ebc2Skrw 3588457ebc2Skrw if (code < 0 || code >= DHO_COUNT) 3598457ebc2Skrw return ""; 3608457ebc2Skrw 3618457ebc2Skrw if (dhcp_options[code].name != NULL) 3628457ebc2Skrw return dhcp_options[code].name; 3638457ebc2Skrw 3648457ebc2Skrw ret = snprintf(unknown, sizeof(unknown), "option-%d", code); 365515e489cSderaadt if (ret < 0 || ret >= (int)sizeof(unknown)) 3668457ebc2Skrw return ""; 3678457ebc2Skrw 3688457ebc2Skrw return unknown; 3698457ebc2Skrw } 3708457ebc2Skrw 3718457ebc2Skrw int 3728457ebc2Skrw name_to_code(char *name) 3738457ebc2Skrw { 3748457ebc2Skrw char unknown[11]; /* "option-NNN" */ 3758457ebc2Skrw int code, ret; 3768457ebc2Skrw 3778457ebc2Skrw for (code = 1; code < DHO_END; code++) { 3788457ebc2Skrw if (dhcp_options[code].name == NULL) { 3798457ebc2Skrw ret = snprintf(unknown, sizeof(unknown), "option-%d", 3808457ebc2Skrw code); 381515e489cSderaadt if (ret < 0 || ret >= (int)sizeof(unknown)) 3828457ebc2Skrw return DHO_END; 3838457ebc2Skrw if (strcasecmp(unknown, name) == 0) 3848457ebc2Skrw return code; 3858457ebc2Skrw } else if (strcasecmp(dhcp_options[code].name, name) == 0) { 3868457ebc2Skrw return code; 3878457ebc2Skrw } 3888457ebc2Skrw } 3898457ebc2Skrw 3908457ebc2Skrw return DHO_END; 3918457ebc2Skrw } 3928457ebc2Skrw 3938457ebc2Skrw char * 3948457ebc2Skrw code_to_format(int code) 3958457ebc2Skrw { 3968457ebc2Skrw if (code < 0 || code >= DHO_COUNT) 3978457ebc2Skrw return ""; 3988457ebc2Skrw 3998457ebc2Skrw if (dhcp_options[code].format == NULL) 4008457ebc2Skrw return "X"; 4018457ebc2Skrw 4028457ebc2Skrw return dhcp_options[code].format; 4038457ebc2Skrw } 4048457ebc2Skrw 4058457ebc2Skrw /* 406d712a45dSkrw * Some option data types cannot be appended or prepended to. For 407d712a45dSkrw * such options change ACTION_PREPEND to ACTION_SUPERSEDE and 408d712a45dSkrw * ACTION_APPEND to ACTION_DEFAULT. 409d712a45dSkrw */ 410d712a45dSkrw int 411d712a45dSkrw code_to_action(int code, int action) 412d712a45dSkrw { 413d712a45dSkrw char *fmt; 414d712a45dSkrw 415d712a45dSkrw fmt = code_to_format(code); 416f1e54185Skrw if (fmt == NULL || strpbrk(fmt, "ADtX") != NULL) 417d712a45dSkrw return action; 418d712a45dSkrw 419d712a45dSkrw /* 420d712a45dSkrw * For our protection all formats which have been excluded shall be 421d712a45dSkrw * deemed included. 422d712a45dSkrw */ 423d712a45dSkrw switch (action) { 424d712a45dSkrw case ACTION_APPEND: 425d712a45dSkrw action = ACTION_DEFAULT; 426d712a45dSkrw break; 427d712a45dSkrw case ACTION_PREPEND: 428d712a45dSkrw action = ACTION_SUPERSEDE; 429d712a45dSkrw break; 430d712a45dSkrw default: 431d712a45dSkrw break; 432d712a45dSkrw } 433d712a45dSkrw 434d712a45dSkrw return action; 435d712a45dSkrw } 436d712a45dSkrw 437d712a45dSkrw /* 438c714dadcShenning * Parse options out of the specified buffer, storing addresses of 43992018899Skrw * option values in options. Return 0 if errors, 1 if not. 440c714dadcShenning */ 44102e02bd5Skrw int 4424f062ee3Skrw parse_option_buffer(struct option_data *options, unsigned char *buffer, 4434f062ee3Skrw int length) 4449a2590e5Sderaadt { 445373f0df1Skrw unsigned char *s, *t, *end; 4468457ebc2Skrw char *name, *fmt; 4470fe2d5abSkrw int code, len, newlen; 4489a2590e5Sderaadt 449373f0df1Skrw s = buffer; 450373f0df1Skrw end = s + length; 451373f0df1Skrw while (s < end) { 4529a2590e5Sderaadt code = s[0]; 4539a2590e5Sderaadt 454373f0df1Skrw /* End options terminate processing. */ 455373f0df1Skrw if (code == DHO_END) 456373f0df1Skrw break; 457373f0df1Skrw 4589a2590e5Sderaadt /* Pad options don't have a length - just skip them. */ 4599a2590e5Sderaadt if (code == DHO_PAD) { 460f1e89499Shenning s++; 4619a2590e5Sderaadt continue; 4629a2590e5Sderaadt } 4639a2590e5Sderaadt 4648457ebc2Skrw name = code_to_name(code); 4658457ebc2Skrw fmt = code_to_format(code); 4668457ebc2Skrw 467c714dadcShenning /* 46899c003b1Skrw * All options other than DHO_PAD and DHO_END have a one-byte 46999c003b1Skrw * length field. It could be 0! Make sure that the length byte 47099c003b1Skrw * is present, and all the data is available. 471c714dadcShenning */ 47299c003b1Skrw if (s + 1 < end) { 4739a2590e5Sderaadt len = s[1]; 47499c003b1Skrw if (s + 1 + len < end) { 47599c003b1Skrw ; /* option data is all there. */ 47699c003b1Skrw } else { 477b53f3a4dSkrw log_warnx("%s: option %s (%d) larger than " 478b53f3a4dSkrw "buffer", log_procname, name, len); 47951a35423Skrw return 0; 4809a2590e5Sderaadt } 48199c003b1Skrw } else { 482b53f3a4dSkrw log_warnx("%s: option %s has no length field", 483b53f3a4dSkrw log_procname, name); 48451a35423Skrw return 0; 48599c003b1Skrw } 486df453039Skrw 487df453039Skrw /* 488587003c7Skrw * Strip trailing NULs from ascii ('t') options. RFC 2132 489df453039Skrw * says "Options containing NVT ASCII data SHOULD NOT include 490df453039Skrw * a trailing NULL; however, the receiver of such options 491df453039Skrw * MUST be prepared to delete trailing nulls if they exist." 492df453039Skrw */ 4938457ebc2Skrw if (fmt[0] == 't') { 49499c003b1Skrw while (len > 0 && s[len + 1] == '\0') 49599c003b1Skrw len--; 496df453039Skrw } 497df453039Skrw 498c714dadcShenning /* 4990fe2d5abSkrw * Concatenate new data + NUL to existing option data. 5000fe2d5abSkrw * 5010fe2d5abSkrw * Note that the NUL is *not* counted in the len field! 502c714dadcShenning */ 5030fe2d5abSkrw newlen = options[code].len + len; 5040fe2d5abSkrw if ((t = realloc(options[code].data, newlen + 1)) == NULL) 50540c65bfbSkrw fatal("option %s", name); 5060fe2d5abSkrw 5074f062ee3Skrw memcpy(t + options[code].len, &s[2], len); 5080fe2d5abSkrw t[newlen] = 0; 5090fe2d5abSkrw 5100fe2d5abSkrw options[code].len = newlen; 5114f062ee3Skrw options[code].data = t; 5120fe2d5abSkrw 513ef234d22Skrw s += s[1] + 2; 5149a2590e5Sderaadt } 51502e02bd5Skrw 51651a35423Skrw return 1; 5179a2590e5Sderaadt } 5189a2590e5Sderaadt 519c714dadcShenning /* 520b414edd1Skrw * Pack as many options as fit in buflen bytes of buf. Return the 52196978980Skrw * offset of the start of the last option copied. A caller can check 52296978980Skrw * to see if it's DHO_END to decide if all the options were copied. 523c714dadcShenning */ 524c714dadcShenning int 525b414edd1Skrw pack_options(unsigned char *buf, int buflen, struct option_data *options) 5269a2590e5Sderaadt { 52796978980Skrw int ix, incr, length, bufix, code, lastopt = -1; 5289a2590e5Sderaadt 529736b0ed2Skrw memset(buf, 0, buflen); 5309a2590e5Sderaadt 53196978980Skrw memcpy(buf, DHCP_OPTIONS_COOKIE, 4); 5326fe46e93Skrw if (options[DHO_DHCP_MESSAGE_TYPE].data != NULL) { 533d6a67f0fSkrw memcpy(&buf[4], DHCP_OPTIONS_MESSAGE_TYPE, 3); 534d6a67f0fSkrw buf[6] = options[DHO_DHCP_MESSAGE_TYPE].data[0]; 535d6a67f0fSkrw bufix = 7; 536d6a67f0fSkrw } else 53796978980Skrw bufix = 4; 5389a2590e5Sderaadt 53996978980Skrw for (code = DHO_SUBNET_MASK; code < DHO_END; code++) { 540561b23c2Skrw if (options[code].data == NULL || 541561b23c2Skrw code == DHO_DHCP_MESSAGE_TYPE) 5429a2590e5Sderaadt continue; 5439a2590e5Sderaadt 544d7d9bbf5Skrw length = options[code].len; 54596978980Skrw if (bufix + length + 2*((length+254)/255) >= buflen) 54651a35423Skrw return lastopt; 5479a2590e5Sderaadt 54896978980Skrw lastopt = bufix; 5499a2590e5Sderaadt ix = 0; 5509a2590e5Sderaadt 5519a2590e5Sderaadt while (length) { 55296978980Skrw incr = length > 255 ? 255 : length; 5539a2590e5Sderaadt 55496978980Skrw buf[bufix++] = code; 55596978980Skrw buf[bufix++] = incr; 55696978980Skrw memcpy(buf + bufix, options[code].data + ix, incr); 5579a2590e5Sderaadt 5589a2590e5Sderaadt length -= incr; 5599a2590e5Sderaadt ix += incr; 5606fc9f4f6Skrw bufix += incr; 5619a2590e5Sderaadt } 5629a2590e5Sderaadt } 56396978980Skrw 56496978980Skrw if (bufix < buflen) { 56596978980Skrw buf[bufix] = DHO_END; 56696978980Skrw lastopt = bufix; 56796978980Skrw } 56896978980Skrw 56951a35423Skrw return lastopt; 5709a2590e5Sderaadt } 5719a2590e5Sderaadt 572c714dadcShenning /* 573482123e8Skrw * Use vis() to encode characters of src and append encoded characters onto 574482123e8Skrw * dst. Also encode ", ', $, ` and \, to ensure resulting strings can be 575482123e8Skrw * represented as '"' delimited strings and safely passed to scripts. Surround 576482123e8Skrw * result with double quotes if emit_punct is true. 577482123e8Skrw */ 578bee06f07Skrw char * 579bee06f07Skrw pretty_print_string(unsigned char *src, size_t srclen, int emit_punct) 580482123e8Skrw { 581bee06f07Skrw static char string[8196]; 582482123e8Skrw char visbuf[5]; 583482123e8Skrw unsigned char *origsrc = src; 584bee06f07Skrw size_t rslt = 0; 585482123e8Skrw 586bee06f07Skrw memset(string, 0, sizeof(string)); 587bee06f07Skrw 5886fe46e93Skrw if (emit_punct != 0) 589bee06f07Skrw rslt = strlcat(string, "\"", sizeof(string)); 590482123e8Skrw 591482123e8Skrw for (; src < origsrc + srclen; src++) { 592482123e8Skrw if (*src && strchr("\"'$`\\", *src)) 593642cc348Skrw vis(visbuf, *src, VIS_ALL | VIS_OCTAL, *src+1); 594642cc348Skrw else 595482123e8Skrw vis(visbuf, *src, VIS_OCTAL, *src+1); 596bee06f07Skrw rslt = strlcat(string, visbuf, sizeof(string)); 597482123e8Skrw } 598482123e8Skrw 5996fe46e93Skrw if (emit_punct != 0) 600bee06f07Skrw rslt = strlcat(string, "\"", sizeof(string)); 601bee06f07Skrw 602bee06f07Skrw if (rslt >= sizeof(string)) 60351a35423Skrw return NULL; 604bee06f07Skrw 60551a35423Skrw return string; 606482123e8Skrw } 607482123e8Skrw 608482123e8Skrw /* 6095714f486Skrw * Must special case *_CLASSLESS_* route options due to the variable size 6105714f486Skrw * of the CIDR element in its CIA format. 6115714f486Skrw */ 6125c6453b8Skrw void 6135c6453b8Skrw pretty_print_classless_routes(unsigned char *src, size_t srclen, 6145c6453b8Skrw unsigned char *buf, size_t buflen) 6155714f486Skrw { 616da2eb076Skrw char bitsbuf[5]; /* to hold "/nn " */ 617f267fa4cSkrw struct in_addr dest, netmask, gateway; 6182aaf2bf4Skrw unsigned int bits, i, len; 6192aaf2bf4Skrw uint32_t m; 6205cbe9918Skrw int rslt; 6215714f486Skrw 622f267fa4cSkrw i = 0; 623f267fa4cSkrw while (i < srclen) { 624f267fa4cSkrw len = extract_classless_route(&src[i], srclen - i, 625f267fa4cSkrw &dest.s_addr, &netmask.s_addr, &gateway.s_addr); 6265cbe9918Skrw if (len == 0) 627f267fa4cSkrw goto bad; 628f267fa4cSkrw i += len; 629da2eb076Skrw 6302aaf2bf4Skrw m = ntohl(netmask.s_addr); 6312aaf2bf4Skrw bits = 32; 6322aaf2bf4Skrw while ((bits > 0) && ((m & 1) == 0)) { 6332aaf2bf4Skrw m >>= 1; 6342aaf2bf4Skrw bits--; 6352aaf2bf4Skrw } 6362aaf2bf4Skrw 6372aaf2bf4Skrw rslt = snprintf(bitsbuf, sizeof(bitsbuf), "/%d ", bits); 638515e489cSderaadt if (rslt < 0 || (unsigned int)rslt >= sizeof(bitsbuf)) 639f267fa4cSkrw goto bad; 640da2eb076Skrw 6415c6453b8Skrw if (strlen(buf) > 0) 6425c6453b8Skrw strlcat(buf, ", ", buflen); 643f267fa4cSkrw strlcat(buf, inet_ntoa(dest), buflen); 6445c6453b8Skrw strlcat(buf, bitsbuf, buflen); 6455c6453b8Skrw if (strlcat(buf, inet_ntoa(gateway), buflen) >= buflen) 646f267fa4cSkrw goto bad; 6475714f486Skrw } 6485714f486Skrw 6495c6453b8Skrw return; 6505c6453b8Skrw 651f267fa4cSkrw bad: 6525c6453b8Skrw memset(buf, 0, buflen); 6535714f486Skrw } 6545714f486Skrw 655f1e54185Skrw /* 656f1e54185Skrw * Print string containing blank separated list of domain names 657f1e54185Skrw * as a comma separated list of double-quote delimited strings. 658f1e54185Skrw * 659f1e54185Skrw * e.g. "eng.apple.com. marketing.apple.com." 660f1e54185Skrw * 661f1e54185Skrw * will be translated to 662f1e54185Skrw * 663f1e54185Skrw * "eng.apple.com.", "marketing.apple.com." 664f1e54185Skrw */ 665f1e54185Skrw void 666f1e54185Skrw pretty_print_domain_list(unsigned char *src, size_t srclen, 667f1e54185Skrw unsigned char *buf, size_t buflen) 668968fe952Skrw { 669f1e54185Skrw char *dupnames, *hn, *inputstring; 670f1e54185Skrw int count; 671968fe952Skrw 672f1e54185Skrw memset(buf, 0, buflen); 673968fe952Skrw 674f1e54185Skrw if (srclen >= DHCP_DOMAIN_SEARCH_LEN || strlen(src) == 0 || 675f1e54185Skrw strlen(src) > DHCP_DOMAIN_SEARCH_LEN) 676f1e54185Skrw return; 677f1e54185Skrw 678f1e54185Skrw dupnames = inputstring = strdup(src); 679f1e54185Skrw if (inputstring == NULL) 680f1e54185Skrw fatal("domain name list"); 681f1e54185Skrw 682f1e54185Skrw count = 0; 683f1e54185Skrw while ((hn = strsep(&inputstring, " \t")) != NULL) { 684f1e54185Skrw if (strlen(hn) == 0) 685f1e54185Skrw continue; 686f1e54185Skrw if (res_hnok(hn) == 0) 687f1e54185Skrw goto bad; 688f1e54185Skrw if (count > 0) 689f1e54185Skrw strlcat(buf, ", ", buflen); 690f1e54185Skrw strlcat(buf, "\"", buflen); 691f1e54185Skrw strlcat(buf, hn, buflen); 692f1e54185Skrw if (strlcat(buf, "\"", buflen) >= buflen) 693f1e54185Skrw goto bad; 694f1e54185Skrw count++; 695f1e54185Skrw if (count > DHCP_DOMAIN_SEARCH_CNT) 696f1e54185Skrw goto bad; 697968fe952Skrw } 698968fe952Skrw 699f1e54185Skrw free(dupnames); 700f1e54185Skrw return; 701968fe952Skrw 702f1e54185Skrw bad: 703f1e54185Skrw free(dupnames); 704f1e54185Skrw memset(buf, 0, buflen); 705968fe952Skrw } 706968fe952Skrw 7075714f486Skrw /* 708c714dadcShenning * Format the specified option so that a human can easily read it. 709c714dadcShenning */ 710c714dadcShenning char * 711acf4c28bSkrw pretty_print_option(unsigned int code, struct option_data *option, 712acf4c28bSkrw int emit_punct) 7139a2590e5Sderaadt { 714bee06f07Skrw static char optbuf[8192]; /* XXX */ 715024801d2Skrw char fmtbuf[32]; 716024801d2Skrw struct in_addr foo; 717acf4c28bSkrw unsigned char *data = option->data; 7189a2590e5Sderaadt unsigned char *dp = data; 7198457ebc2Skrw char *op = optbuf, *buf, *name, *fmt; 720024801d2Skrw int hunksize = 0, numhunk = -1, numelem = 0; 721024801d2Skrw int i, j, k, opleft = sizeof(optbuf); 722acf4c28bSkrw int len = option->len; 723f3a8c5fdSkrw int opcount = 0; 724bce09e58Skrw int32_t int32val; 725024801d2Skrw uint32_t uint32val; 726024801d2Skrw uint16_t uint16val; 727024801d2Skrw char comma; 7289a2590e5Sderaadt 7292f18daabSkrw memset(optbuf, 0, sizeof(optbuf)); 7302f18daabSkrw 7319a2590e5Sderaadt /* Code should be between 0 and 255. */ 7322f18daabSkrw if (code > 255) { 733b4afd8f1Skrw log_warnx("%s: pretty_print_option: bad code %d", log_procname, 734b4afd8f1Skrw code); 7352f18daabSkrw goto done; 7362f18daabSkrw } 7379a2590e5Sderaadt 7386fe46e93Skrw if (emit_punct != 0) 7399a2590e5Sderaadt comma = ','; 7409a2590e5Sderaadt else 7419a2590e5Sderaadt comma = ' '; 7429a2590e5Sderaadt 7435714f486Skrw /* Handle the princess class options with weirdo formats. */ 7445714f486Skrw switch (code) { 7455714f486Skrw case DHO_CLASSLESS_STATIC_ROUTES: 7465714f486Skrw case DHO_CLASSLESS_MS_STATIC_ROUTES: 7471abdd88fSkrw pretty_print_classless_routes(dp, len, optbuf, sizeof(optbuf)); 7481abdd88fSkrw goto done; 749f1e54185Skrw case DHO_DOMAIN_SEARCH: 750f1e54185Skrw pretty_print_domain_list(dp, len, optbuf, sizeof(optbuf)); 751f1e54185Skrw goto done; 7525714f486Skrw default: 7535714f486Skrw break; 7545714f486Skrw } 7555714f486Skrw 7568457ebc2Skrw name = code_to_name(code); 7578457ebc2Skrw fmt = code_to_format(code); 7588457ebc2Skrw 7599a2590e5Sderaadt /* Figure out the size of the data. */ 7608457ebc2Skrw for (i = 0; fmt[i]; i++) { 7616fe46e93Skrw if (numhunk == 0) { 762b4afd8f1Skrw log_warnx("%s: %s: excess information in format " 763b53f3a4dSkrw "string: %s", log_procname, name, &fmt[i]); 7642f18daabSkrw goto done; 7659a2590e5Sderaadt } 7669a2590e5Sderaadt numelem++; 7678457ebc2Skrw fmtbuf[i] = fmt[i]; 7688457ebc2Skrw switch (fmt[i]) { 7699a2590e5Sderaadt case 'A': 7709a2590e5Sderaadt --numelem; 7719a2590e5Sderaadt fmtbuf[i] = 0; 7729a2590e5Sderaadt numhunk = 0; 77329432cd9Sphessler if (hunksize == 0) { 774b53f3a4dSkrw log_warnx("%s: %s: no size indicator before A" 775b53f3a4dSkrw " in format string: %s", log_procname, 776b53f3a4dSkrw name, fmt); 7772f18daabSkrw goto done; 77829432cd9Sphessler } 7799a2590e5Sderaadt break; 7809a2590e5Sderaadt case 'X': 781c714dadcShenning for (k = 0; k < len; k++) 7826fe46e93Skrw if (isascii(data[k]) == 0 || 7836fe46e93Skrw isprint(data[k]) == 0) 7849a2590e5Sderaadt break; 785b54c879eShenning if (k == len) { 7869a2590e5Sderaadt fmtbuf[i] = 't'; 7879a2590e5Sderaadt numhunk = -2; 7889a2590e5Sderaadt } else { 7899a2590e5Sderaadt hunksize++; 7909a2590e5Sderaadt comma = ':'; 7919a2590e5Sderaadt numhunk = 0; 7929a2590e5Sderaadt } 7939a2590e5Sderaadt fmtbuf[i + 1] = 0; 7949a2590e5Sderaadt break; 7959a2590e5Sderaadt case 't': 7969a2590e5Sderaadt fmtbuf[i + 1] = 0; 7979a2590e5Sderaadt numhunk = -2; 7989a2590e5Sderaadt break; 7999a2590e5Sderaadt case 'I': 8009a2590e5Sderaadt case 'l': 8019a2590e5Sderaadt case 'L': 8029a2590e5Sderaadt hunksize += 4; 8039a2590e5Sderaadt break; 8049a2590e5Sderaadt case 'S': 8059a2590e5Sderaadt hunksize += 2; 8069a2590e5Sderaadt break; 8079a2590e5Sderaadt case 'B': 8089a2590e5Sderaadt case 'f': 8099a2590e5Sderaadt hunksize++; 8109a2590e5Sderaadt break; 8119a2590e5Sderaadt case 'e': 8129a2590e5Sderaadt break; 8139a2590e5Sderaadt default: 814b53f3a4dSkrw log_warnx("%s: %s: garbage in format string: %s", 815b53f3a4dSkrw log_procname, name, &fmt[i]); 8162f18daabSkrw goto done; 8179a2590e5Sderaadt } 8189a2590e5Sderaadt } 8199a2590e5Sderaadt 820d22f105fSkrw /* Check for too few bytes. */ 8219a2590e5Sderaadt if (hunksize > len) { 822b53f3a4dSkrw log_warnx("%s: %s: expecting at least %d bytes; got %d", 823b53f3a4dSkrw log_procname, name, hunksize, len); 8242f18daabSkrw goto done; 8259a2590e5Sderaadt } 826d22f105fSkrw /* Check for too many bytes. */ 8272f18daabSkrw if (numhunk == -1 && hunksize < len) { 828b53f3a4dSkrw log_warnx("%s: %s: expecting only %d bytes: got %d", 829b53f3a4dSkrw log_procname, name, hunksize, len); 8302f18daabSkrw goto done; 8312f18daabSkrw } 8329a2590e5Sderaadt 8339a2590e5Sderaadt /* If this is an array, compute its size. */ 8346fe46e93Skrw if (numhunk == 0) 8359a2590e5Sderaadt numhunk = len / hunksize; 8369a2590e5Sderaadt /* See if we got an exact number of hunks. */ 8372f18daabSkrw if (numhunk > 0 && numhunk * hunksize != len) { 838b53f3a4dSkrw log_warnx("%s: %s: expecting %d bytes: got %d", log_procname, 839b53f3a4dSkrw name, numhunk * hunksize, len); 8402f18daabSkrw goto done; 8412f18daabSkrw } 8429a2590e5Sderaadt 8439a2590e5Sderaadt /* A one-hunk array prints the same as a single hunk. */ 8449a2590e5Sderaadt if (numhunk < 0) 8459a2590e5Sderaadt numhunk = 1; 8469a2590e5Sderaadt 8479a2590e5Sderaadt /* Cycle through the array (or hunk) printing the data. */ 8489a2590e5Sderaadt for (i = 0; i < numhunk; i++) { 8499a2590e5Sderaadt for (j = 0; j < numelem; j++) { 8509a2590e5Sderaadt switch (fmtbuf[j]) { 8519a2590e5Sderaadt case 't': 852bee06f07Skrw buf = pretty_print_string(dp, len, emit_punct); 853bee06f07Skrw if (buf == NULL) 854bee06f07Skrw opcount = -1; 855bee06f07Skrw else 856bee06f07Skrw opcount = strlcat(op, buf, opleft); 8579a2590e5Sderaadt break; 8589a2590e5Sderaadt case 'I': 859e95625edSkrw memcpy(&foo.s_addr, dp, sizeof(foo.s_addr)); 860f3a8c5fdSkrw opcount = snprintf(op, opleft, "%s", 861f3a8c5fdSkrw inet_ntoa(foo)); 862e95625edSkrw dp += sizeof(foo.s_addr); 8639a2590e5Sderaadt break; 8649a2590e5Sderaadt case 'l': 865bce09e58Skrw memcpy(&int32val, dp, sizeof(int32val)); 866bce09e58Skrw opcount = snprintf(op, opleft, "%d", 867bce09e58Skrw ntohl(int32val)); 868bce09e58Skrw dp += sizeof(int32val); 8699a2590e5Sderaadt break; 8709a2590e5Sderaadt case 'L': 871bce09e58Skrw memcpy(&uint32val, dp, sizeof(uint32val)); 872bce09e58Skrw opcount = snprintf(op, opleft, "%u", 873bce09e58Skrw ntohl(uint32val)); 874bce09e58Skrw dp += sizeof(uint32val); 8759a2590e5Sderaadt break; 8769a2590e5Sderaadt case 'S': 877bce09e58Skrw memcpy(&uint16val, dp, sizeof(uint16val)); 878bce09e58Skrw opcount = snprintf(op, opleft, "%hu", 879bce09e58Skrw ntohs(uint16val)); 880bce09e58Skrw dp += sizeof(uint16val); 8819a2590e5Sderaadt break; 8829a2590e5Sderaadt case 'B': 883221bd6c0Skrw opcount = snprintf(op, opleft, "%u", *dp); 884de3ca9dbSkrw dp++; 8859a2590e5Sderaadt break; 886920d03efSkrw case 'X': 887de3ca9dbSkrw opcount = snprintf(op, opleft, "%x", *dp); 888de3ca9dbSkrw dp++; 8899a2590e5Sderaadt break; 8909a2590e5Sderaadt case 'f': 891f3a8c5fdSkrw opcount = snprintf(op, opleft, "%s", 892f3a8c5fdSkrw *dp ? "true" : "false"); 893de3ca9dbSkrw dp++; 8949a2590e5Sderaadt break; 8959a2590e5Sderaadt default: 896b53f3a4dSkrw log_warnx("%s: unexpected format code %c", 897b53f3a4dSkrw log_procname, fmtbuf[j]); 8989a2590e5Sderaadt goto toobig; 899f3a8c5fdSkrw } 900515e489cSderaadt if (opcount < 0 || opcount >= opleft) 901f3a8c5fdSkrw goto toobig; 902f3a8c5fdSkrw opleft -= opcount; 903f3a8c5fdSkrw op += opcount; 9049a2590e5Sderaadt if (j + 1 < numelem && comma != ':') { 905f3a8c5fdSkrw opcount = snprintf(op, opleft, " "); 906515e489cSderaadt if (opcount < 0 || opcount >= opleft) 907f3a8c5fdSkrw goto toobig; 908f3a8c5fdSkrw opleft -= opcount; 909f3a8c5fdSkrw op += opcount; 9109a2590e5Sderaadt } 9119a2590e5Sderaadt } 9129a2590e5Sderaadt if (i + 1 < numhunk) { 913f3a8c5fdSkrw opcount = snprintf(op, opleft, "%c", comma); 914515e489cSderaadt if (opcount < 0 || opcount >= opleft) 9159a2590e5Sderaadt goto toobig; 916f3a8c5fdSkrw opleft -= opcount; 917f3a8c5fdSkrw op += opcount; 918f3a8c5fdSkrw } 9199a2590e5Sderaadt } 9202f18daabSkrw 9212f18daabSkrw done: 92251a35423Skrw return optbuf; 9232f18daabSkrw 9249a2590e5Sderaadt toobig: 9252f18daabSkrw memset(optbuf, 0, sizeof(optbuf)); 92651a35423Skrw return optbuf; 9279a2590e5Sderaadt } 9289a2590e5Sderaadt 929b414edd1Skrw struct option_data * 930b414edd1Skrw unpack_options(struct dhcp_packet *packet) 9319a2590e5Sderaadt { 932cb26da20Skrw static struct option_data options[DHO_COUNT]; 933b414edd1Skrw int i; 9349a2590e5Sderaadt 935cb26da20Skrw for (i = 0; i < DHO_COUNT; i++) { 936b414edd1Skrw free(options[i].data); 937b414edd1Skrw options[i].data = NULL; 938b414edd1Skrw options[i].len = 0; 939b414edd1Skrw } 94002e02bd5Skrw 94102e02bd5Skrw if (memcmp(&packet->options, DHCP_OPTIONS_COOKIE, 4) == 0) { 94202e02bd5Skrw /* Parse the BOOTP/DHCP options field. */ 943b414edd1Skrw parse_option_buffer(options, &packet->options[4], 944b414edd1Skrw sizeof(packet->options) - 4); 94502e02bd5Skrw 946b414edd1Skrw /* DHCP packets can also use overload areas for options. */ 9476fe46e93Skrw if (options[DHO_DHCP_MESSAGE_TYPE].data != NULL && 9486fe46e93Skrw options[DHO_DHCP_OPTION_OVERLOAD].data != NULL) { 949b4afd8f1Skrw if ((options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1) != 950b4afd8f1Skrw 0) 951b414edd1Skrw parse_option_buffer(options, 95202e02bd5Skrw (unsigned char *)packet->file, 95302e02bd5Skrw sizeof(packet->file)); 954b4afd8f1Skrw if ((options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2) != 955b4afd8f1Skrw 0) 956b414edd1Skrw parse_option_buffer(options, 95702e02bd5Skrw (unsigned char *)packet->sname, 95802e02bd5Skrw sizeof(packet->sname)); 95902e02bd5Skrw } 96002e02bd5Skrw } 96102e02bd5Skrw 962b414edd1Skrw return options; 9639a2590e5Sderaadt } 964d712a45dSkrw 965d712a45dSkrw void 966*6562b533Skrw merge_option_data(char *fmt, struct option_data *first, 967d712a45dSkrw struct option_data *second, struct option_data *dest) 968d712a45dSkrw { 969*6562b533Skrw int rslt; 970*6562b533Skrw 971d712a45dSkrw free(dest->data); 972*6562b533Skrw dest->data = NULL; 973d712a45dSkrw dest->len = first->len + second->len; 974*6562b533Skrw if (dest->len == 0) 975*6562b533Skrw return; 976*6562b533Skrw 977*6562b533Skrw switch (fmt[0]) { 978*6562b533Skrw case 'D': 979*6562b533Skrw rslt = asprintf((char **)&dest->data, "%s%s%s", 980*6562b533Skrw (first->len > 0) ? (char *)first->data : "", 981*6562b533Skrw (first->len > 0 && second->len > 0) ? " " : "", 982*6562b533Skrw (second->len > 0) ? (char *)second->data : ""); 983*6562b533Skrw if (rslt == -1) 984*6562b533Skrw fatal("merged 'D'"); 985*6562b533Skrw dest->len = strlen(dest->data); 986*6562b533Skrw break; 987*6562b533Skrw case 't': 988*6562b533Skrw rslt = asprintf((char **)&dest->data, "%s%s", 989*6562b533Skrw (first->len > 0) ? (char *)first->data : "", 990*6562b533Skrw (second->len > 0) ? (char *)second->data : ""); 991*6562b533Skrw if (rslt == -1) 992*6562b533Skrw fatal("merged 't'"); 993*6562b533Skrw break; 994*6562b533Skrw default: 995d712a45dSkrw dest->data = calloc(1, dest->len); 996d712a45dSkrw if (dest->data == NULL) 997d712a45dSkrw fatal("merged option data"); 998d712a45dSkrw memcpy(dest->data, first->data, first->len); 999d712a45dSkrw memcpy(dest->data + first->len, second->data, second->len); 1000*6562b533Skrw break; 1001*6562b533Skrw } 1002d712a45dSkrw } 1003