1*8457ebc2Skrw /* $OpenBSD: options.c,v 1.97 2017/07/08 20:38:31 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> 54711cae1eSkrw #include <signal.h> 55711cae1eSkrw #include <stdio.h> 56711cae1eSkrw #include <stdlib.h> 57711cae1eSkrw #include <string.h> 588d2bd14bSkrw #include <vis.h> 598d2bd14bSkrw 60711cae1eSkrw #include "dhcp.h" 61711cae1eSkrw #include "dhcpd.h" 62385a6373Skrw #include "log.h" 63711cae1eSkrw 6402e02bd5Skrw int parse_option_buffer(struct option_data *, unsigned char *, int); 65968fe952Skrw int expand_search_domain_name(unsigned char *, size_t, int *, unsigned char *); 669a2590e5Sderaadt 67c714dadcShenning /* 68*8457ebc2Skrw * DHCP Option names, formats and codes, from RFC1533. 69*8457ebc2Skrw * 70*8457ebc2Skrw * Format codes: 71*8457ebc2Skrw * 72*8457ebc2Skrw * e - end of data 73*8457ebc2Skrw * I - IP address 74*8457ebc2Skrw * l - 32-bit signed integer 75*8457ebc2Skrw * L - 32-bit unsigned integer 76*8457ebc2Skrw * S - 16-bit unsigned integer 77*8457ebc2Skrw * B - 8-bit unsigned integer 78*8457ebc2Skrw * t - ASCII text 79*8457ebc2Skrw * f - flag (true or false) 80*8457ebc2Skrw * A - array of whatever precedes (e.g., IA means array of IP addresses) 81*8457ebc2Skrw * C - CIDR description 82*8457ebc2Skrw */ 83*8457ebc2Skrw 84*8457ebc2Skrw static const struct { 85*8457ebc2Skrw char *name; 86*8457ebc2Skrw char *format; 87*8457ebc2Skrw } dhcp_options[DHO_COUNT] = { 88*8457ebc2Skrw /* 0 */ { "pad", "" }, 89*8457ebc2Skrw /* 1 */ { "subnet-mask", "I" }, 90*8457ebc2Skrw /* 2 */ { "time-offset", "l" }, 91*8457ebc2Skrw /* 3 */ { "routers", "IA" }, 92*8457ebc2Skrw /* 4 */ { "time-servers", "IA" }, 93*8457ebc2Skrw /* 5 */ { "ien116-name-servers", "IA" }, 94*8457ebc2Skrw /* 6 */ { "domain-name-servers", "IA" }, 95*8457ebc2Skrw /* 7 */ { "log-servers", "IA" }, 96*8457ebc2Skrw /* 8 */ { "cookie-servers", "IA" }, 97*8457ebc2Skrw /* 9 */ { "lpr-servers", "IA" }, 98*8457ebc2Skrw /* 10 */ { "impress-servers", "IA" }, 99*8457ebc2Skrw /* 11 */ { "resource-location-servers", "IA" }, 100*8457ebc2Skrw /* 12 */ { "host-name", "t" }, 101*8457ebc2Skrw /* 13 */ { "boot-size", "S" }, 102*8457ebc2Skrw /* 14 */ { "merit-dump", "t" }, 103*8457ebc2Skrw /* 15 */ { "domain-name", "t" }, 104*8457ebc2Skrw /* 16 */ { "swap-server", "I" }, 105*8457ebc2Skrw /* 17 */ { "root-path", "t" }, 106*8457ebc2Skrw /* 18 */ { "extensions-path", "t" }, 107*8457ebc2Skrw /* 19 */ { "ip-forwarding", "f" }, 108*8457ebc2Skrw /* 20 */ { "non-local-source-routing", "f" }, 109*8457ebc2Skrw /* 21 */ { "policy-filter", "IIA" }, 110*8457ebc2Skrw /* 22 */ { "max-dgram-reassembly", "S" }, 111*8457ebc2Skrw /* 23 */ { "default-ip-ttl", "B" }, 112*8457ebc2Skrw /* 24 */ { "path-mtu-aging-timeout", "L" }, 113*8457ebc2Skrw /* 25 */ { "path-mtu-plateau-table", "SA" }, 114*8457ebc2Skrw /* 26 */ { "interface-mtu", "S" }, 115*8457ebc2Skrw /* 27 */ { "all-subnets-local", "f" }, 116*8457ebc2Skrw /* 28 */ { "broadcast-address", "I" }, 117*8457ebc2Skrw /* 29 */ { "perform-mask-discovery", "f" }, 118*8457ebc2Skrw /* 30 */ { "mask-supplier", "f" }, 119*8457ebc2Skrw /* 31 */ { "router-discovery", "f" }, 120*8457ebc2Skrw /* 32 */ { "router-solicitation-address", "I" }, 121*8457ebc2Skrw /* 33 */ { "static-routes", "IIA" }, 122*8457ebc2Skrw /* 34 */ { "trailer-encapsulation", "f" }, 123*8457ebc2Skrw /* 35 */ { "arp-cache-timeout", "L" }, 124*8457ebc2Skrw /* 36 */ { "ieee802-3-encapsulation", "f" }, 125*8457ebc2Skrw /* 37 */ { "default-tcp-ttl", "B" }, 126*8457ebc2Skrw /* 38 */ { "tcp-keepalive-interval", "L" }, 127*8457ebc2Skrw /* 39 */ { "tcp-keepalive-garbage", "f" }, 128*8457ebc2Skrw /* 40 */ { "nis-domain", "t" }, 129*8457ebc2Skrw /* 41 */ { "nis-servers", "IA" }, 130*8457ebc2Skrw /* 42 */ { "ntp-servers", "IA" }, 131*8457ebc2Skrw /* 43 */ { "vendor-encapsulated-options", "X" }, 132*8457ebc2Skrw /* 44 */ { "netbios-name-servers", "IA" }, 133*8457ebc2Skrw /* 45 */ { "netbios-dd-server", "IA" }, 134*8457ebc2Skrw /* 46 */ { "netbios-node-type", "B" }, 135*8457ebc2Skrw /* 47 */ { "netbios-scope", "t" }, 136*8457ebc2Skrw /* 48 */ { "font-servers", "IA" }, 137*8457ebc2Skrw /* 49 */ { "x-display-manager", "IA" }, 138*8457ebc2Skrw /* 50 */ { "dhcp-requested-address", "I" }, 139*8457ebc2Skrw /* 51 */ { "dhcp-lease-time", "L" }, 140*8457ebc2Skrw /* 52 */ { "dhcp-option-overload", "B" }, 141*8457ebc2Skrw /* 53 */ { "dhcp-message-type", "B" }, 142*8457ebc2Skrw /* 54 */ { "dhcp-server-identifier", "I" }, 143*8457ebc2Skrw /* 55 */ { "dhcp-parameter-request-list", "BA" }, 144*8457ebc2Skrw /* 56 */ { "dhcp-message", "t" }, 145*8457ebc2Skrw /* 57 */ { "dhcp-max-message-size", "S" }, 146*8457ebc2Skrw /* 58 */ { "dhcp-renewal-time", "L" }, 147*8457ebc2Skrw /* 59 */ { "dhcp-rebinding-time", "L" }, 148*8457ebc2Skrw /* 60 */ { "dhcp-class-identifier", "t" }, 149*8457ebc2Skrw /* 61 */ { "dhcp-client-identifier", "X" }, 150*8457ebc2Skrw /* 62 */ { NULL, NULL }, 151*8457ebc2Skrw /* 63 */ { NULL, NULL }, 152*8457ebc2Skrw /* 64 */ { "nisplus-domain", "t" }, 153*8457ebc2Skrw /* 65 */ { "nisplus-servers", "IA" }, 154*8457ebc2Skrw /* 66 */ { "tftp-server-name", "t" }, 155*8457ebc2Skrw /* 67 */ { "bootfile-name", "t" }, 156*8457ebc2Skrw /* 68 */ { "mobile-ip-home-agent", "IA" }, 157*8457ebc2Skrw /* 69 */ { "smtp-server", "IA" }, 158*8457ebc2Skrw /* 70 */ { "pop-server", "IA" }, 159*8457ebc2Skrw /* 71 */ { "nntp-server", "IA" }, 160*8457ebc2Skrw /* 72 */ { "www-server", "IA" }, 161*8457ebc2Skrw /* 73 */ { "finger-server", "IA" }, 162*8457ebc2Skrw /* 74 */ { "irc-server", "IA" }, 163*8457ebc2Skrw /* 75 */ { "streettalk-server", "IA" }, 164*8457ebc2Skrw /* 76 */ { "streettalk-directory-assistance-server", "IA" }, 165*8457ebc2Skrw /* 77 */ { "user-class", "t" }, 166*8457ebc2Skrw /* 78 */ { NULL, NULL }, 167*8457ebc2Skrw /* 79 */ { NULL, NULL }, 168*8457ebc2Skrw /* 80 */ { NULL, NULL }, 169*8457ebc2Skrw /* 81 */ { NULL, NULL }, 170*8457ebc2Skrw /* 82 */ { "relay-agent-information", "X" }, 171*8457ebc2Skrw /* 83 */ { NULL, NULL }, 172*8457ebc2Skrw /* 84 */ { NULL, NULL }, 173*8457ebc2Skrw /* 85 */ { "nds-servers", "IA" }, 174*8457ebc2Skrw /* 86 */ { "nds-tree-name", "X" }, 175*8457ebc2Skrw /* 87 */ { "nds-context", "X" }, 176*8457ebc2Skrw /* 88 */ { NULL, NULL }, 177*8457ebc2Skrw /* 89 */ { NULL, NULL }, 178*8457ebc2Skrw /* 90 */ { NULL, NULL }, 179*8457ebc2Skrw /* 91 */ { NULL, NULL }, 180*8457ebc2Skrw /* 92 */ { NULL, NULL }, 181*8457ebc2Skrw /* 93 */ { NULL, NULL }, 182*8457ebc2Skrw /* 94 */ { NULL, NULL }, 183*8457ebc2Skrw /* 95 */ { NULL, NULL }, 184*8457ebc2Skrw /* 96 */ { NULL, NULL }, 185*8457ebc2Skrw /* 97 */ { NULL, NULL }, 186*8457ebc2Skrw /* 98 */ { NULL, NULL }, 187*8457ebc2Skrw /* 99 */ { NULL, NULL }, 188*8457ebc2Skrw /* 100 */ { NULL, NULL }, 189*8457ebc2Skrw /* 101 */ { NULL, NULL }, 190*8457ebc2Skrw /* 102 */ { NULL, NULL }, 191*8457ebc2Skrw /* 103 */ { NULL, NULL }, 192*8457ebc2Skrw /* 104 */ { NULL, NULL }, 193*8457ebc2Skrw /* 105 */ { NULL, NULL }, 194*8457ebc2Skrw /* 106 */ { NULL, NULL }, 195*8457ebc2Skrw /* 107 */ { NULL, NULL }, 196*8457ebc2Skrw /* 108 */ { NULL, NULL }, 197*8457ebc2Skrw /* 109 */ { NULL, NULL }, 198*8457ebc2Skrw /* 110 */ { NULL, NULL }, 199*8457ebc2Skrw /* 111 */ { NULL, NULL }, 200*8457ebc2Skrw /* 112 */ { NULL, NULL }, 201*8457ebc2Skrw /* 113 */ { NULL, NULL }, 202*8457ebc2Skrw /* 114 */ { NULL, NULL }, 203*8457ebc2Skrw /* 115 */ { NULL, NULL }, 204*8457ebc2Skrw /* 116 */ { NULL, NULL }, 205*8457ebc2Skrw /* 117 */ { NULL, NULL }, 206*8457ebc2Skrw /* 118 */ { NULL, NULL }, 207*8457ebc2Skrw /* 119 */ { "domain-search", "X" }, 208*8457ebc2Skrw /* 120 */ { NULL, NULL }, 209*8457ebc2Skrw /* 121 */ { "classless-static-routes", "CIA" }, 210*8457ebc2Skrw /* 122 */ { NULL, NULL }, 211*8457ebc2Skrw /* 123 */ { NULL, NULL }, 212*8457ebc2Skrw /* 124 */ { NULL, NULL }, 213*8457ebc2Skrw /* 125 */ { NULL, NULL }, 214*8457ebc2Skrw /* 126 */ { NULL, NULL }, 215*8457ebc2Skrw /* 127 */ { NULL, NULL }, 216*8457ebc2Skrw /* 128 */ { NULL, NULL }, 217*8457ebc2Skrw /* 129 */ { NULL, NULL }, 218*8457ebc2Skrw /* 130 */ { NULL, NULL }, 219*8457ebc2Skrw /* 131 */ { NULL, NULL }, 220*8457ebc2Skrw /* 132 */ { NULL, NULL }, 221*8457ebc2Skrw /* 133 */ { NULL, NULL }, 222*8457ebc2Skrw /* 134 */ { NULL, NULL }, 223*8457ebc2Skrw /* 135 */ { NULL, NULL }, 224*8457ebc2Skrw /* 136 */ { NULL, NULL }, 225*8457ebc2Skrw /* 137 */ { NULL, NULL }, 226*8457ebc2Skrw /* 138 */ { NULL, NULL }, 227*8457ebc2Skrw /* 139 */ { NULL, NULL }, 228*8457ebc2Skrw /* 140 */ { NULL, NULL }, 229*8457ebc2Skrw /* 141 */ { NULL, NULL }, 230*8457ebc2Skrw /* 142 */ { NULL, NULL }, 231*8457ebc2Skrw /* 143 */ { NULL, NULL }, 232*8457ebc2Skrw /* 144 */ { "tftp-config-file", "t" }, 233*8457ebc2Skrw /* 145 */ { NULL, NULL }, 234*8457ebc2Skrw /* 146 */ { NULL, NULL }, 235*8457ebc2Skrw /* 147 */ { NULL, NULL }, 236*8457ebc2Skrw /* 148 */ { NULL, NULL }, 237*8457ebc2Skrw /* 149 */ { NULL, NULL }, 238*8457ebc2Skrw /* 150 */ { "voip-configuration-server", "IA" }, 239*8457ebc2Skrw /* 151 */ { NULL, NULL }, 240*8457ebc2Skrw /* 152 */ { NULL, NULL }, 241*8457ebc2Skrw /* 153 */ { NULL, NULL }, 242*8457ebc2Skrw /* 154 */ { NULL, NULL }, 243*8457ebc2Skrw /* 155 */ { NULL, NULL }, 244*8457ebc2Skrw /* 156 */ { NULL, NULL }, 245*8457ebc2Skrw /* 157 */ { NULL, NULL }, 246*8457ebc2Skrw /* 158 */ { NULL, NULL }, 247*8457ebc2Skrw /* 159 */ { NULL, NULL }, 248*8457ebc2Skrw /* 160 */ { NULL, NULL }, 249*8457ebc2Skrw /* 161 */ { NULL, NULL }, 250*8457ebc2Skrw /* 162 */ { NULL, NULL }, 251*8457ebc2Skrw /* 163 */ { NULL, NULL }, 252*8457ebc2Skrw /* 164 */ { NULL, NULL }, 253*8457ebc2Skrw /* 165 */ { NULL, NULL }, 254*8457ebc2Skrw /* 166 */ { NULL, NULL }, 255*8457ebc2Skrw /* 167 */ { NULL, NULL }, 256*8457ebc2Skrw /* 168 */ { NULL, NULL }, 257*8457ebc2Skrw /* 169 */ { NULL, NULL }, 258*8457ebc2Skrw /* 170 */ { NULL, NULL }, 259*8457ebc2Skrw /* 171 */ { NULL, NULL }, 260*8457ebc2Skrw /* 172 */ { NULL, NULL }, 261*8457ebc2Skrw /* 173 */ { NULL, NULL }, 262*8457ebc2Skrw /* 174 */ { NULL, NULL }, 263*8457ebc2Skrw /* 175 */ { NULL, NULL }, 264*8457ebc2Skrw /* 176 */ { NULL, NULL }, 265*8457ebc2Skrw /* 177 */ { NULL, NULL }, 266*8457ebc2Skrw /* 178 */ { NULL, NULL }, 267*8457ebc2Skrw /* 179 */ { NULL, NULL }, 268*8457ebc2Skrw /* 180 */ { NULL, NULL }, 269*8457ebc2Skrw /* 181 */ { NULL, NULL }, 270*8457ebc2Skrw /* 182 */ { NULL, NULL }, 271*8457ebc2Skrw /* 183 */ { NULL, NULL }, 272*8457ebc2Skrw /* 184 */ { NULL, NULL }, 273*8457ebc2Skrw /* 185 */ { NULL, NULL }, 274*8457ebc2Skrw /* 186 */ { NULL, NULL }, 275*8457ebc2Skrw /* 187 */ { NULL, NULL }, 276*8457ebc2Skrw /* 188 */ { NULL, NULL }, 277*8457ebc2Skrw /* 189 */ { NULL, NULL }, 278*8457ebc2Skrw /* 190 */ { NULL, NULL }, 279*8457ebc2Skrw /* 191 */ { NULL, NULL }, 280*8457ebc2Skrw /* 192 */ { NULL, NULL }, 281*8457ebc2Skrw /* 193 */ { NULL, NULL }, 282*8457ebc2Skrw /* 194 */ { NULL, NULL }, 283*8457ebc2Skrw /* 195 */ { NULL, NULL }, 284*8457ebc2Skrw /* 196 */ { NULL, NULL }, 285*8457ebc2Skrw /* 197 */ { NULL, NULL }, 286*8457ebc2Skrw /* 198 */ { NULL, NULL }, 287*8457ebc2Skrw /* 199 */ { NULL, NULL }, 288*8457ebc2Skrw /* 200 */ { NULL, NULL }, 289*8457ebc2Skrw /* 201 */ { NULL, NULL }, 290*8457ebc2Skrw /* 202 */ { NULL, NULL }, 291*8457ebc2Skrw /* 203 */ { NULL, NULL }, 292*8457ebc2Skrw /* 204 */ { NULL, NULL }, 293*8457ebc2Skrw /* 205 */ { NULL, NULL }, 294*8457ebc2Skrw /* 206 */ { NULL, NULL }, 295*8457ebc2Skrw /* 207 */ { NULL, NULL }, 296*8457ebc2Skrw /* 208 */ { NULL, NULL }, 297*8457ebc2Skrw /* 209 */ { NULL, NULL }, 298*8457ebc2Skrw /* 210 */ { NULL, NULL }, 299*8457ebc2Skrw /* 211 */ { NULL, NULL }, 300*8457ebc2Skrw /* 212 */ { NULL, NULL }, 301*8457ebc2Skrw /* 213 */ { NULL, NULL }, 302*8457ebc2Skrw /* 214 */ { NULL, NULL }, 303*8457ebc2Skrw /* 215 */ { NULL, NULL }, 304*8457ebc2Skrw /* 216 */ { NULL, NULL }, 305*8457ebc2Skrw /* 217 */ { NULL, NULL }, 306*8457ebc2Skrw /* 218 */ { NULL, NULL }, 307*8457ebc2Skrw /* 219 */ { NULL, NULL }, 308*8457ebc2Skrw /* 220 */ { NULL, NULL }, 309*8457ebc2Skrw /* 221 */ { NULL, NULL }, 310*8457ebc2Skrw /* 222 */ { NULL, NULL }, 311*8457ebc2Skrw /* 223 */ { NULL, NULL }, 312*8457ebc2Skrw /* 224 */ { NULL, NULL }, 313*8457ebc2Skrw /* 225 */ { NULL, NULL }, 314*8457ebc2Skrw /* 226 */ { NULL, NULL }, 315*8457ebc2Skrw /* 227 */ { NULL, NULL }, 316*8457ebc2Skrw /* 228 */ { NULL, NULL }, 317*8457ebc2Skrw /* 229 */ { NULL, NULL }, 318*8457ebc2Skrw /* 230 */ { NULL, NULL }, 319*8457ebc2Skrw /* 231 */ { NULL, NULL }, 320*8457ebc2Skrw /* 232 */ { NULL, NULL }, 321*8457ebc2Skrw /* 233 */ { NULL, NULL }, 322*8457ebc2Skrw /* 234 */ { NULL, NULL }, 323*8457ebc2Skrw /* 235 */ { NULL, NULL }, 324*8457ebc2Skrw /* 236 */ { NULL, NULL }, 325*8457ebc2Skrw /* 237 */ { NULL, NULL }, 326*8457ebc2Skrw /* 238 */ { NULL, NULL }, 327*8457ebc2Skrw /* 239 */ { NULL, NULL }, 328*8457ebc2Skrw /* 240 */ { NULL, NULL }, 329*8457ebc2Skrw /* 241 */ { NULL, NULL }, 330*8457ebc2Skrw /* 242 */ { NULL, NULL }, 331*8457ebc2Skrw /* 243 */ { NULL, NULL }, 332*8457ebc2Skrw /* 244 */ { NULL, NULL }, 333*8457ebc2Skrw /* 245 */ { NULL, NULL }, 334*8457ebc2Skrw /* 246 */ { NULL, NULL }, 335*8457ebc2Skrw /* 247 */ { NULL, NULL }, 336*8457ebc2Skrw /* 248 */ { NULL, NULL }, 337*8457ebc2Skrw /* 249 */ { "classless-ms-static-routes", "CIA" }, 338*8457ebc2Skrw /* 250 */ { NULL, NULL }, 339*8457ebc2Skrw /* 251 */ { NULL, NULL }, 340*8457ebc2Skrw /* 252 */ { "autoproxy-script", "t" }, 341*8457ebc2Skrw /* 253 */ { NULL, NULL }, 342*8457ebc2Skrw /* 254 */ { NULL, NULL }, 343*8457ebc2Skrw /* 255 */ { "option-end", "e" }, 344*8457ebc2Skrw }; 345*8457ebc2Skrw 346*8457ebc2Skrw char * 347*8457ebc2Skrw code_to_name(int code) 348*8457ebc2Skrw { 349*8457ebc2Skrw static char unknown[11]; /* "option-NNN" */ 350*8457ebc2Skrw int ret; 351*8457ebc2Skrw 352*8457ebc2Skrw if (code < 0 || code >= DHO_COUNT) 353*8457ebc2Skrw return ""; 354*8457ebc2Skrw 355*8457ebc2Skrw if (dhcp_options[code].name != NULL) 356*8457ebc2Skrw return dhcp_options[code].name; 357*8457ebc2Skrw 358*8457ebc2Skrw ret = snprintf(unknown, sizeof(unknown), "option-%d", code); 359*8457ebc2Skrw if (ret == -1 || ret >= (int)sizeof(unknown)) 360*8457ebc2Skrw return ""; 361*8457ebc2Skrw 362*8457ebc2Skrw return unknown; 363*8457ebc2Skrw } 364*8457ebc2Skrw 365*8457ebc2Skrw int 366*8457ebc2Skrw name_to_code(char *name) 367*8457ebc2Skrw { 368*8457ebc2Skrw char unknown[11]; /* "option-NNN" */ 369*8457ebc2Skrw int code, ret; 370*8457ebc2Skrw 371*8457ebc2Skrw for (code = 1; code < DHO_END; code++) { 372*8457ebc2Skrw if (dhcp_options[code].name == NULL) { 373*8457ebc2Skrw ret = snprintf(unknown, sizeof(unknown), "option-%d", 374*8457ebc2Skrw code); 375*8457ebc2Skrw if (ret == -1 || ret >= (int)sizeof(unknown)) 376*8457ebc2Skrw return DHO_END; 377*8457ebc2Skrw if (strcasecmp(unknown, name) == 0) 378*8457ebc2Skrw return code; 379*8457ebc2Skrw } else if (strcasecmp(dhcp_options[code].name, name) == 0) { 380*8457ebc2Skrw return code; 381*8457ebc2Skrw } 382*8457ebc2Skrw } 383*8457ebc2Skrw 384*8457ebc2Skrw return DHO_END; 385*8457ebc2Skrw } 386*8457ebc2Skrw 387*8457ebc2Skrw char * 388*8457ebc2Skrw code_to_format(int code) 389*8457ebc2Skrw { 390*8457ebc2Skrw if (code < 0 || code >= DHO_COUNT) 391*8457ebc2Skrw return ""; 392*8457ebc2Skrw 393*8457ebc2Skrw if (dhcp_options[code].format == NULL) 394*8457ebc2Skrw return "X"; 395*8457ebc2Skrw 396*8457ebc2Skrw return dhcp_options[code].format; 397*8457ebc2Skrw } 398*8457ebc2Skrw 399*8457ebc2Skrw /* 400c714dadcShenning * Parse options out of the specified buffer, storing addresses of 40192018899Skrw * option values in options. Return 0 if errors, 1 if not. 402c714dadcShenning */ 40302e02bd5Skrw int 4044f062ee3Skrw parse_option_buffer(struct option_data *options, unsigned char *buffer, 4054f062ee3Skrw int length) 4069a2590e5Sderaadt { 407285f06efSderaadt unsigned char *s, *t, *end = buffer + length; 408*8457ebc2Skrw char *name, *fmt; 409285f06efSderaadt int len, code; 4109a2590e5Sderaadt 4119a2590e5Sderaadt for (s = buffer; *s != DHO_END && s < end; ) { 4129a2590e5Sderaadt code = s[0]; 4139a2590e5Sderaadt 4149a2590e5Sderaadt /* Pad options don't have a length - just skip them. */ 4159a2590e5Sderaadt if (code == DHO_PAD) { 416f1e89499Shenning s++; 4179a2590e5Sderaadt continue; 4189a2590e5Sderaadt } 4199a2590e5Sderaadt 420*8457ebc2Skrw name = code_to_name(code); 421*8457ebc2Skrw fmt = code_to_format(code); 422*8457ebc2Skrw 423c714dadcShenning /* 42499c003b1Skrw * All options other than DHO_PAD and DHO_END have a one-byte 42599c003b1Skrw * length field. It could be 0! Make sure that the length byte 42699c003b1Skrw * is present, and all the data is available. 427c714dadcShenning */ 42899c003b1Skrw if (s + 1 < end) { 4299a2590e5Sderaadt len = s[1]; 43099c003b1Skrw if (s + 1 + len < end) { 43199c003b1Skrw ; /* option data is all there. */ 43299c003b1Skrw } else { 433385a6373Skrw log_warnx("option %s (%d) larger than buffer.", 434*8457ebc2Skrw name, len); 43502e02bd5Skrw return (0); 4369a2590e5Sderaadt } 43799c003b1Skrw } else { 438*8457ebc2Skrw log_warnx("option %s has no length field.", name); 43999c003b1Skrw return (0); 44099c003b1Skrw } 441df453039Skrw 442df453039Skrw /* 443df453039Skrw * Strip trailing NULs from ascii ('t') options. They 444df453039Skrw * will be treated as DHO_PAD options. i.e. ignored. RFC 2132 445df453039Skrw * says "Options containing NVT ASCII data SHOULD NOT include 446df453039Skrw * a trailing NULL; however, the receiver of such options 447df453039Skrw * MUST be prepared to delete trailing nulls if they exist." 448df453039Skrw */ 449*8457ebc2Skrw if (fmt[0] == 't') { 45099c003b1Skrw while (len > 0 && s[len + 1] == '\0') 45199c003b1Skrw len--; 452df453039Skrw } 453df453039Skrw 454c714dadcShenning /* 455c714dadcShenning * If we haven't seen this option before, just make 456c714dadcShenning * space for it and copy it there. 457c714dadcShenning */ 4584f062ee3Skrw if (!options[code].data) { 4598e916ab9Shenning if (!(t = calloc(1, len + 1))) 460385a6373Skrw fatalx("Can't allocate storage for option %s.", 461*8457ebc2Skrw name); 462c714dadcShenning /* 463c714dadcShenning * Copy and NUL-terminate the option (in case 464cff08477Sstevesk * it's an ASCII string). 465c714dadcShenning */ 4669a2590e5Sderaadt memcpy(t, &s[2], len); 4679a2590e5Sderaadt t[len] = 0; 4684f062ee3Skrw options[code].len = len; 4694f062ee3Skrw options[code].data = t; 4709a2590e5Sderaadt } else { 471c714dadcShenning /* 472c714dadcShenning * If it's a repeat, concatenate it to whatever 47392018899Skrw * we last saw. 474c714dadcShenning */ 4754f062ee3Skrw t = calloc(1, len + options[code].len + 1); 4769a2590e5Sderaadt if (!t) 477385a6373Skrw fatalx("Can't expand storage for option %s.", 478*8457ebc2Skrw name); 4794f062ee3Skrw memcpy(t, options[code].data, options[code].len); 4804f062ee3Skrw memcpy(t + options[code].len, &s[2], len); 4814f062ee3Skrw options[code].len += len; 4824f062ee3Skrw t[options[code].len] = 0; 4834f062ee3Skrw free(options[code].data); 4844f062ee3Skrw options[code].data = t; 4859a2590e5Sderaadt } 4869a2590e5Sderaadt s += len + 2; 4879a2590e5Sderaadt } 48802e02bd5Skrw 48902e02bd5Skrw return (1); 4909a2590e5Sderaadt } 4919a2590e5Sderaadt 492c714dadcShenning /* 493b414edd1Skrw * Pack as many options as fit in buflen bytes of buf. Return the 49496978980Skrw * offset of the start of the last option copied. A caller can check 49596978980Skrw * to see if it's DHO_END to decide if all the options were copied. 496c714dadcShenning */ 497c714dadcShenning int 498b414edd1Skrw pack_options(unsigned char *buf, int buflen, struct option_data *options) 4999a2590e5Sderaadt { 50096978980Skrw int ix, incr, length, bufix, code, lastopt = -1; 5019a2590e5Sderaadt 502736b0ed2Skrw memset(buf, 0, buflen); 5039a2590e5Sderaadt 50496978980Skrw memcpy(buf, DHCP_OPTIONS_COOKIE, 4); 505d6a67f0fSkrw if (options[DHO_DHCP_MESSAGE_TYPE].data) { 506d6a67f0fSkrw memcpy(&buf[4], DHCP_OPTIONS_MESSAGE_TYPE, 3); 507d6a67f0fSkrw buf[6] = options[DHO_DHCP_MESSAGE_TYPE].data[0]; 508d6a67f0fSkrw bufix = 7; 509d6a67f0fSkrw } else 51096978980Skrw bufix = 4; 5119a2590e5Sderaadt 51296978980Skrw for (code = DHO_SUBNET_MASK; code < DHO_END; code++) { 513d6a67f0fSkrw if (!options[code].data || code == DHO_DHCP_MESSAGE_TYPE) 5149a2590e5Sderaadt continue; 5159a2590e5Sderaadt 516d7d9bbf5Skrw length = options[code].len; 51796978980Skrw if (bufix + length + 2*((length+254)/255) >= buflen) 51896978980Skrw return (lastopt); 5199a2590e5Sderaadt 52096978980Skrw lastopt = bufix; 5219a2590e5Sderaadt ix = 0; 5229a2590e5Sderaadt 5239a2590e5Sderaadt while (length) { 52496978980Skrw incr = length > 255 ? 255 : length; 5259a2590e5Sderaadt 52696978980Skrw buf[bufix++] = code; 52796978980Skrw buf[bufix++] = incr; 52896978980Skrw memcpy(buf + bufix, options[code].data + ix, incr); 5299a2590e5Sderaadt 5309a2590e5Sderaadt length -= incr; 5319a2590e5Sderaadt ix += incr; 5326fc9f4f6Skrw bufix += incr; 5339a2590e5Sderaadt } 5349a2590e5Sderaadt } 53596978980Skrw 53696978980Skrw if (bufix < buflen) { 53796978980Skrw buf[bufix] = DHO_END; 53896978980Skrw lastopt = bufix; 53996978980Skrw } 54096978980Skrw 54196978980Skrw return (lastopt); 5429a2590e5Sderaadt } 5439a2590e5Sderaadt 544c714dadcShenning /* 545482123e8Skrw * Use vis() to encode characters of src and append encoded characters onto 546482123e8Skrw * dst. Also encode ", ', $, ` and \, to ensure resulting strings can be 547482123e8Skrw * represented as '"' delimited strings and safely passed to scripts. Surround 548482123e8Skrw * result with double quotes if emit_punct is true. 549482123e8Skrw */ 550bee06f07Skrw char * 551bee06f07Skrw pretty_print_string(unsigned char *src, size_t srclen, int emit_punct) 552482123e8Skrw { 553bee06f07Skrw static char string[8196]; 554482123e8Skrw char visbuf[5]; 555482123e8Skrw unsigned char *origsrc = src; 556bee06f07Skrw size_t rslt = 0; 557482123e8Skrw 558bee06f07Skrw memset(string, 0, sizeof(string)); 559bee06f07Skrw 560bee06f07Skrw if (emit_punct) 561bee06f07Skrw rslt = strlcat(string, "\"", sizeof(string)); 562482123e8Skrw 563482123e8Skrw for (; src < origsrc + srclen; src++) { 564482123e8Skrw if (*src && strchr("\"'$`\\", *src)) 565642cc348Skrw vis(visbuf, *src, VIS_ALL | VIS_OCTAL, *src+1); 566642cc348Skrw else 567482123e8Skrw vis(visbuf, *src, VIS_OCTAL, *src+1); 568bee06f07Skrw rslt = strlcat(string, visbuf, sizeof(string)); 569482123e8Skrw } 570482123e8Skrw 571bee06f07Skrw if (emit_punct) 572bee06f07Skrw rslt = strlcat(string, "\"", sizeof(string)); 573bee06f07Skrw 574bee06f07Skrw if (rslt >= sizeof(string)) 575bee06f07Skrw return (NULL); 576bee06f07Skrw 577bee06f07Skrw return (string); 578482123e8Skrw } 579482123e8Skrw 580482123e8Skrw /* 5815714f486Skrw * Must special case *_CLASSLESS_* route options due to the variable size 5825714f486Skrw * of the CIDR element in its CIA format. 5835714f486Skrw */ 584da2eb076Skrw char * 585da2eb076Skrw pretty_print_classless_routes(unsigned char *src, size_t srclen) 5865714f486Skrw { 587da2eb076Skrw static char string[8196]; 588da2eb076Skrw char bitsbuf[5]; /* to hold "/nn " */ 589da2eb076Skrw struct in_addr net, gateway; 590e0a6d2f1Skrw unsigned int bytes; 591e0a6d2f1Skrw int bits, rslt; 5925714f486Skrw 593da2eb076Skrw memset(string, 0, sizeof(string)); 594da2eb076Skrw 595da2eb076Skrw while (srclen) { 5965714f486Skrw bits = *src; 5975714f486Skrw src++; 5985714f486Skrw srclen--; 599da2eb076Skrw 6005714f486Skrw bytes = (bits + 7) / 8; 601da2eb076Skrw if (srclen < (bytes + sizeof(gateway.s_addr)) || 602da2eb076Skrw bytes > sizeof(net.s_addr)) 603da2eb076Skrw return (NULL); 604da2eb076Skrw rslt = snprintf(bitsbuf, sizeof(bitsbuf), "/%d ", bits); 6051be0b429Skrw if (rslt == -1 || (unsigned int)rslt >= sizeof(bitsbuf)) 606da2eb076Skrw return (NULL); 607da2eb076Skrw 608da2eb076Skrw memset(&net, 0, sizeof(net)); 609da2eb076Skrw memcpy(&net.s_addr, src, bytes); 6105714f486Skrw src += bytes; 6115714f486Skrw srclen -= bytes; 612da2eb076Skrw 6135714f486Skrw memcpy(&gateway.s_addr, src, sizeof(gateway.s_addr)); 6145714f486Skrw src += sizeof(gateway.s_addr); 6155714f486Skrw srclen -= sizeof(gateway.s_addr); 616da2eb076Skrw 617da2eb076Skrw if (strlen(string) > 0) 618da2eb076Skrw strlcat(string, ", ", sizeof(string)); 619da2eb076Skrw strlcat(string, inet_ntoa(net), sizeof(string)); 620da2eb076Skrw strlcat(string, bitsbuf, sizeof(string)); 6211be0b429Skrw if (strlcat(string, inet_ntoa(gateway), sizeof(string)) >= 6221be0b429Skrw sizeof(string)) 623da2eb076Skrw return (NULL); 6245714f486Skrw } 6255714f486Skrw 626da2eb076Skrw return (string); 6275714f486Skrw } 6285714f486Skrw 629968fe952Skrw int 630968fe952Skrw expand_search_domain_name(unsigned char *src, size_t srclen, int *offset, 631968fe952Skrw unsigned char *domain_search) 632968fe952Skrw { 633e0a6d2f1Skrw unsigned int i; 634e0a6d2f1Skrw int domain_name_len, label_len, pointer, pointed_len; 635968fe952Skrw char *cursor; 636968fe952Skrw 637968fe952Skrw cursor = domain_search + strlen(domain_search); 638968fe952Skrw domain_name_len = 0; 639968fe952Skrw 640968fe952Skrw i = *offset; 641968fe952Skrw while (i <= srclen) { 642968fe952Skrw label_len = src[i]; 643968fe952Skrw if (label_len == 0) { 644968fe952Skrw /* 645968fe952Skrw * A zero-length label marks the end of this 646968fe952Skrw * domain name. 647968fe952Skrw */ 648968fe952Skrw *offset = i + 1; 649968fe952Skrw return (domain_name_len); 650968fe952Skrw } else if (label_len & 0xC0) { 651968fe952Skrw /* This is a pointer to another list of labels. */ 652968fe952Skrw if (i + 1 >= srclen) { 653968fe952Skrw /* The pointer is truncated. */ 654385a6373Skrw log_warnx("Truncated pointer in DHCP Domain " 655968fe952Skrw "Search option."); 656968fe952Skrw return (-1); 657968fe952Skrw } 658968fe952Skrw 659968fe952Skrw pointer = ((label_len & ~(0xC0)) << 8) + src[i + 1]; 660968fe952Skrw if (pointer >= *offset) { 661968fe952Skrw /* 662968fe952Skrw * The pointer must indicates a prior 663968fe952Skrw * occurance. 664968fe952Skrw */ 665385a6373Skrw log_warnx("Invalid forward pointer in DHCP " 666968fe952Skrw "Domain Search option compression."); 667968fe952Skrw return (-1); 668968fe952Skrw } 669968fe952Skrw 670968fe952Skrw pointed_len = expand_search_domain_name(src, srclen, 671968fe952Skrw &pointer, domain_search); 672968fe952Skrw domain_name_len += pointed_len; 673968fe952Skrw 674968fe952Skrw *offset = i + 2; 675968fe952Skrw return (domain_name_len); 676968fe952Skrw } 677968fe952Skrw if (i + label_len + 1 > srclen) { 678385a6373Skrw log_warnx("Truncated label in DHCP Domain Search " 679968fe952Skrw "option."); 680968fe952Skrw return (-1); 681968fe952Skrw } 682968fe952Skrw /* 683968fe952Skrw * Update the domain name length with the length of the 684968fe952Skrw * current label, plus a trailing dot ('.'). 685968fe952Skrw */ 686968fe952Skrw domain_name_len += label_len + 1; 687968fe952Skrw 688968fe952Skrw if (strlen(domain_search) + domain_name_len >= 689968fe952Skrw DHCP_DOMAIN_SEARCH_LEN) { 690385a6373Skrw log_warnx("Domain search list too long."); 691968fe952Skrw return (-1); 692968fe952Skrw } 693968fe952Skrw 694968fe952Skrw /* Copy the label found. */ 695968fe952Skrw memcpy(cursor, src + i + 1, label_len); 696968fe952Skrw cursor[label_len] = '.'; 697968fe952Skrw 698968fe952Skrw /* Move cursor. */ 699968fe952Skrw i += label_len + 1; 700968fe952Skrw cursor += label_len + 1; 701968fe952Skrw } 702968fe952Skrw 703385a6373Skrw log_warnx("Truncated DHCP Domain Search option."); 704968fe952Skrw 705968fe952Skrw return (-1); 706968fe952Skrw } 707968fe952Skrw 708968fe952Skrw /* 709968fe952Skrw * Must special case DHO_DOMAIN_SEARCH because it is encoded as described 710968fe952Skrw * in RFC 1035 section 4.1.4. 711968fe952Skrw */ 7124d36d16aSkrw char * 7134d36d16aSkrw pretty_print_domain_search(unsigned char *src, size_t srclen) 714968fe952Skrw { 7154d36d16aSkrw static char domain_search[DHCP_DOMAIN_SEARCH_LEN]; 716e0a6d2f1Skrw unsigned int offset; 717e0a6d2f1Skrw int len, expanded_len, domains; 7184d36d16aSkrw unsigned char *cursor; 719968fe952Skrw 7204d36d16aSkrw memset(domain_search, 0, sizeof(domain_search)); 721968fe952Skrw 722968fe952Skrw /* Compute expanded length. */ 723968fe952Skrw expanded_len = len = 0; 724968fe952Skrw domains = 0; 725968fe952Skrw offset = 0; 726968fe952Skrw while (offset < srclen) { 727968fe952Skrw cursor = domain_search + strlen(domain_search); 728968fe952Skrw if (domain_search[0]) { 729968fe952Skrw *cursor = ' '; 730968fe952Skrw expanded_len++; 731968fe952Skrw } 732968fe952Skrw len = expand_search_domain_name(src, srclen, &offset, 733968fe952Skrw domain_search); 7344d36d16aSkrw if (len == -1) 7354d36d16aSkrw return (NULL); 736968fe952Skrw domains++; 737968fe952Skrw expanded_len += len; 7384d36d16aSkrw if (domains > DHCP_DOMAIN_SEARCH_CNT) 7394d36d16aSkrw return (NULL); 740968fe952Skrw } 741968fe952Skrw 7424d36d16aSkrw return (domain_search); 743968fe952Skrw } 744968fe952Skrw 7455714f486Skrw /* 746c714dadcShenning * Format the specified option so that a human can easily read it. 747c714dadcShenning */ 748c714dadcShenning char * 749acf4c28bSkrw pretty_print_option(unsigned int code, struct option_data *option, 750acf4c28bSkrw int emit_punct) 7519a2590e5Sderaadt { 752bee06f07Skrw static char optbuf[8192]; /* XXX */ 753024801d2Skrw char fmtbuf[32]; 754024801d2Skrw struct in_addr foo; 755acf4c28bSkrw unsigned char *data = option->data; 7569a2590e5Sderaadt unsigned char *dp = data; 757*8457ebc2Skrw char *op = optbuf, *buf, *name, *fmt; 758024801d2Skrw int hunksize = 0, numhunk = -1, numelem = 0; 759024801d2Skrw int i, j, k, opleft = sizeof(optbuf); 760acf4c28bSkrw int len = option->len; 761f3a8c5fdSkrw int opcount = 0; 762bce09e58Skrw int32_t int32val; 763024801d2Skrw uint32_t uint32val; 764024801d2Skrw uint16_t uint16val; 765024801d2Skrw char comma; 7669a2590e5Sderaadt 7672f18daabSkrw memset(optbuf, 0, sizeof(optbuf)); 7682f18daabSkrw 7699a2590e5Sderaadt /* Code should be between 0 and 255. */ 7702f18daabSkrw if (code > 255) { 771385a6373Skrw log_warnx("pretty_print_option: bad code %d", code); 7722f18daabSkrw goto done; 7732f18daabSkrw } 7749a2590e5Sderaadt 775acf4c28bSkrw if (emit_punct) 7769a2590e5Sderaadt comma = ','; 7779a2590e5Sderaadt else 7789a2590e5Sderaadt comma = ' '; 7799a2590e5Sderaadt 7805714f486Skrw /* Handle the princess class options with weirdo formats. */ 7815714f486Skrw switch (code) { 7825714f486Skrw case DHO_CLASSLESS_STATIC_ROUTES: 7835714f486Skrw case DHO_CLASSLESS_MS_STATIC_ROUTES: 784da2eb076Skrw buf = pretty_print_classless_routes(dp, len); 785da2eb076Skrw if (buf == NULL) 7865714f486Skrw goto toobig; 787da2eb076Skrw strlcat(optbuf, buf, sizeof(optbuf)); 7885714f486Skrw goto done; 7895714f486Skrw default: 7905714f486Skrw break; 7915714f486Skrw } 7925714f486Skrw 793*8457ebc2Skrw name = code_to_name(code); 794*8457ebc2Skrw fmt = code_to_format(code); 795*8457ebc2Skrw 7969a2590e5Sderaadt /* Figure out the size of the data. */ 797*8457ebc2Skrw for (i = 0; fmt[i]; i++) { 7989a2590e5Sderaadt if (!numhunk) { 799833082e5Skrw log_warnx("%s: Excess information in format string: " 800*8457ebc2Skrw "%s", name, &fmt[i]); 8012f18daabSkrw goto done; 8029a2590e5Sderaadt } 8039a2590e5Sderaadt numelem++; 804*8457ebc2Skrw fmtbuf[i] = fmt[i]; 805*8457ebc2Skrw switch (fmt[i]) { 8069a2590e5Sderaadt case 'A': 8079a2590e5Sderaadt --numelem; 8089a2590e5Sderaadt fmtbuf[i] = 0; 8099a2590e5Sderaadt numhunk = 0; 81029432cd9Sphessler if (hunksize == 0) { 811385a6373Skrw log_warnx("%s: no size indicator before A" 812*8457ebc2Skrw " in format string: %s", name, fmt); 8132f18daabSkrw goto done; 81429432cd9Sphessler } 8159a2590e5Sderaadt break; 8169a2590e5Sderaadt case 'X': 817c714dadcShenning for (k = 0; k < len; k++) 8189a2590e5Sderaadt if (!isascii(data[k]) || 8199a2590e5Sderaadt !isprint(data[k])) 8209a2590e5Sderaadt break; 821b54c879eShenning if (k == len) { 8229a2590e5Sderaadt fmtbuf[i] = 't'; 8239a2590e5Sderaadt numhunk = -2; 8249a2590e5Sderaadt } else { 8259a2590e5Sderaadt hunksize++; 8269a2590e5Sderaadt comma = ':'; 8279a2590e5Sderaadt numhunk = 0; 8289a2590e5Sderaadt } 8299a2590e5Sderaadt fmtbuf[i + 1] = 0; 8309a2590e5Sderaadt break; 8319a2590e5Sderaadt case 't': 8329a2590e5Sderaadt fmtbuf[i + 1] = 0; 8339a2590e5Sderaadt numhunk = -2; 8349a2590e5Sderaadt break; 8359a2590e5Sderaadt case 'I': 8369a2590e5Sderaadt case 'l': 8379a2590e5Sderaadt case 'L': 8389a2590e5Sderaadt hunksize += 4; 8399a2590e5Sderaadt break; 8409a2590e5Sderaadt case 'S': 8419a2590e5Sderaadt hunksize += 2; 8429a2590e5Sderaadt break; 8439a2590e5Sderaadt case 'B': 8449a2590e5Sderaadt case 'f': 8459a2590e5Sderaadt hunksize++; 8469a2590e5Sderaadt break; 8479a2590e5Sderaadt case 'e': 8489a2590e5Sderaadt break; 8499a2590e5Sderaadt default: 850*8457ebc2Skrw log_warnx("%s: garbage in format string: %s", name, 851*8457ebc2Skrw &fmt[i]); 8522f18daabSkrw goto done; 8539a2590e5Sderaadt } 8549a2590e5Sderaadt } 8559a2590e5Sderaadt 856d22f105fSkrw /* Check for too few bytes. */ 8579a2590e5Sderaadt if (hunksize > len) { 858*8457ebc2Skrw log_warnx("%s: expecting at least %d bytes; got %d", name, 859*8457ebc2Skrw hunksize, len); 8602f18daabSkrw goto done; 8619a2590e5Sderaadt } 862d22f105fSkrw /* Check for too many bytes. */ 8632f18daabSkrw if (numhunk == -1 && hunksize < len) { 864*8457ebc2Skrw log_warnx("%s: expecting only %d bytes: got %d", name, 865*8457ebc2Skrw hunksize, len); 8662f18daabSkrw goto done; 8672f18daabSkrw } 8689a2590e5Sderaadt 8699a2590e5Sderaadt /* If this is an array, compute its size. */ 8709a2590e5Sderaadt if (!numhunk) 8719a2590e5Sderaadt numhunk = len / hunksize; 8729a2590e5Sderaadt /* See if we got an exact number of hunks. */ 8732f18daabSkrw if (numhunk > 0 && numhunk * hunksize != len) { 874*8457ebc2Skrw log_warnx("%s: expecting %d bytes: got %d", name, 875*8457ebc2Skrw numhunk * hunksize, len); 8762f18daabSkrw goto done; 8772f18daabSkrw } 8789a2590e5Sderaadt 8799a2590e5Sderaadt /* A one-hunk array prints the same as a single hunk. */ 8809a2590e5Sderaadt if (numhunk < 0) 8819a2590e5Sderaadt numhunk = 1; 8829a2590e5Sderaadt 8839a2590e5Sderaadt /* Cycle through the array (or hunk) printing the data. */ 8849a2590e5Sderaadt for (i = 0; i < numhunk; i++) { 8859a2590e5Sderaadt for (j = 0; j < numelem; j++) { 8869a2590e5Sderaadt switch (fmtbuf[j]) { 8879a2590e5Sderaadt case 't': 888bee06f07Skrw buf = pretty_print_string(dp, len, emit_punct); 889bee06f07Skrw if (buf == NULL) 890bee06f07Skrw opcount = -1; 891bee06f07Skrw else 892bee06f07Skrw opcount = strlcat(op, buf, opleft); 8939a2590e5Sderaadt break; 8949a2590e5Sderaadt case 'I': 895e95625edSkrw memcpy(&foo.s_addr, dp, sizeof(foo.s_addr)); 896f3a8c5fdSkrw opcount = snprintf(op, opleft, "%s", 897f3a8c5fdSkrw inet_ntoa(foo)); 898e95625edSkrw dp += sizeof(foo.s_addr); 8999a2590e5Sderaadt break; 9009a2590e5Sderaadt case 'l': 901bce09e58Skrw memcpy(&int32val, dp, sizeof(int32val)); 902bce09e58Skrw opcount = snprintf(op, opleft, "%d", 903bce09e58Skrw ntohl(int32val)); 904bce09e58Skrw dp += sizeof(int32val); 9059a2590e5Sderaadt break; 9069a2590e5Sderaadt case 'L': 907bce09e58Skrw memcpy(&uint32val, dp, sizeof(uint32val)); 908bce09e58Skrw opcount = snprintf(op, opleft, "%u", 909bce09e58Skrw ntohl(uint32val)); 910bce09e58Skrw dp += sizeof(uint32val); 9119a2590e5Sderaadt break; 9129a2590e5Sderaadt case 'S': 913bce09e58Skrw memcpy(&uint16val, dp, sizeof(uint16val)); 914bce09e58Skrw opcount = snprintf(op, opleft, "%hu", 915bce09e58Skrw ntohs(uint16val)); 916bce09e58Skrw dp += sizeof(uint16val); 9179a2590e5Sderaadt break; 9189a2590e5Sderaadt case 'B': 919221bd6c0Skrw opcount = snprintf(op, opleft, "%u", *dp); 920de3ca9dbSkrw dp++; 9219a2590e5Sderaadt break; 922920d03efSkrw case 'X': 923de3ca9dbSkrw opcount = snprintf(op, opleft, "%x", *dp); 924de3ca9dbSkrw dp++; 9259a2590e5Sderaadt break; 9269a2590e5Sderaadt case 'f': 927f3a8c5fdSkrw opcount = snprintf(op, opleft, "%s", 928f3a8c5fdSkrw *dp ? "true" : "false"); 929de3ca9dbSkrw dp++; 9309a2590e5Sderaadt break; 9319a2590e5Sderaadt default: 932833082e5Skrw log_warnx("Unexpected format code %c", 933833082e5Skrw fmtbuf[j]); 9349a2590e5Sderaadt goto toobig; 935f3a8c5fdSkrw } 936f3a8c5fdSkrw if (opcount >= opleft || opcount == -1) 937f3a8c5fdSkrw goto toobig; 938f3a8c5fdSkrw opleft -= opcount; 939f3a8c5fdSkrw op += opcount; 9409a2590e5Sderaadt if (j + 1 < numelem && comma != ':') { 941f3a8c5fdSkrw opcount = snprintf(op, opleft, " "); 942f3a8c5fdSkrw if (opcount >= opleft || opcount == -1) 943f3a8c5fdSkrw goto toobig; 944f3a8c5fdSkrw opleft -= opcount; 945f3a8c5fdSkrw op += opcount; 9469a2590e5Sderaadt } 9479a2590e5Sderaadt } 9489a2590e5Sderaadt if (i + 1 < numhunk) { 949f3a8c5fdSkrw opcount = snprintf(op, opleft, "%c", comma); 950f3a8c5fdSkrw if (opcount >= opleft || opcount == -1) 9519a2590e5Sderaadt goto toobig; 952f3a8c5fdSkrw opleft -= opcount; 953f3a8c5fdSkrw op += opcount; 954f3a8c5fdSkrw } 9559a2590e5Sderaadt } 9562f18daabSkrw 9572f18daabSkrw done: 958c714dadcShenning return (optbuf); 9592f18daabSkrw 9609a2590e5Sderaadt toobig: 9612f18daabSkrw memset(optbuf, 0, sizeof(optbuf)); 9622f18daabSkrw return (optbuf); 9639a2590e5Sderaadt } 9649a2590e5Sderaadt 965b414edd1Skrw struct option_data * 966b414edd1Skrw unpack_options(struct dhcp_packet *packet) 9679a2590e5Sderaadt { 968cb26da20Skrw static struct option_data options[DHO_COUNT]; 969b414edd1Skrw int i; 9709a2590e5Sderaadt 971cb26da20Skrw for (i = 0; i < DHO_COUNT; i++) { 972b414edd1Skrw free(options[i].data); 973b414edd1Skrw options[i].data = NULL; 974b414edd1Skrw options[i].len = 0; 975b414edd1Skrw } 97602e02bd5Skrw 97702e02bd5Skrw if (memcmp(&packet->options, DHCP_OPTIONS_COOKIE, 4) == 0) { 97802e02bd5Skrw /* Parse the BOOTP/DHCP options field. */ 979b414edd1Skrw parse_option_buffer(options, &packet->options[4], 980b414edd1Skrw sizeof(packet->options) - 4); 98102e02bd5Skrw 982b414edd1Skrw /* DHCP packets can also use overload areas for options. */ 983b414edd1Skrw if (options[DHO_DHCP_MESSAGE_TYPE].data && 98402e02bd5Skrw options[DHO_DHCP_OPTION_OVERLOAD].data) { 98502e02bd5Skrw if (options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1) 986b414edd1Skrw parse_option_buffer(options, 98702e02bd5Skrw (unsigned char *)packet->file, 98802e02bd5Skrw sizeof(packet->file)); 989b414edd1Skrw if (options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2) 990b414edd1Skrw parse_option_buffer(options, 99102e02bd5Skrw (unsigned char *)packet->sname, 99202e02bd5Skrw sizeof(packet->sname)); 99302e02bd5Skrw } 99402e02bd5Skrw } 99502e02bd5Skrw 996b414edd1Skrw return options; 9979a2590e5Sderaadt } 998