Vishal Bhoj | 82c8071 | 2015-12-15 21:13:33 +0530 | [diff] [blame^] | 1 | /** @file
|
| 2 | Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
|
| 3 | This program and the accompanying materials are licensed and made available
|
| 4 | under the terms and conditions of the BSD License which accompanies this
|
| 5 | distribution. The full text of the license may be found at
|
| 6 | http://opensource.org/licenses/bsd-license.php.
|
| 7 |
|
| 8 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
| 9 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
| 10 | **/
|
| 11 | /*
|
| 12 | * Copyright (c) 1996 by Internet Software Consortium.
|
| 13 | *
|
| 14 | * Permission to use, copy, modify, and distribute this software for any
|
| 15 | * purpose with or without fee is hereby granted, provided that the above
|
| 16 | * copyright notice and this permission notice appear in all copies.
|
| 17 | *
|
| 18 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
| 19 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
| 20 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
| 21 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
| 22 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
| 23 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
| 24 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
| 25 | * SOFTWARE.
|
| 26 | */
|
| 27 |
|
| 28 | /*
|
| 29 | * Portions copyright (c) 1999, 2000
|
| 30 | * Intel Corporation.
|
| 31 | * All rights reserved.
|
| 32 | *
|
| 33 | * Redistribution and use in source and binary forms, with or without
|
| 34 | * modification, are permitted provided that the following conditions
|
| 35 | * are met:
|
| 36 | *
|
| 37 | * 1. Redistributions of source code must retain the above copyright
|
| 38 | * notice, this list of conditions and the following disclaimer.
|
| 39 | *
|
| 40 | * 2. Redistributions in binary form must reproduce the above copyright
|
| 41 | * notice, this list of conditions and the following disclaimer in the
|
| 42 | * documentation and/or other materials provided with the distribution.
|
| 43 | *
|
| 44 | * 3. All advertising materials mentioning features or use of this software
|
| 45 | * must display the following acknowledgement:
|
| 46 | *
|
| 47 | * This product includes software developed by Intel Corporation and
|
| 48 | * its contributors.
|
| 49 | *
|
| 50 | * 4. Neither the name of Intel Corporation or its contributors may be
|
| 51 | * used to endorse or promote products derived from this software
|
| 52 | * without specific prior written permission.
|
| 53 | *
|
| 54 | * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS''
|
| 55 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 56 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 57 | * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE
|
| 58 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 59 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 60 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 61 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 62 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 63 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
| 64 | * THE POSSIBILITY OF SUCH DAMAGE.
|
| 65 | *
|
| 66 | */
|
| 67 |
|
| 68 | /*
|
| 69 | * Based on the Dynamic DNS reference implementation by Viraj Bais
|
| 70 | * <viraj_bais@ccm.fm.intel.com>
|
| 71 | */
|
| 72 |
|
| 73 | #include <sys/types.h>
|
| 74 | #include <sys/param.h>
|
| 75 |
|
| 76 | #include <netinet/in.h>
|
| 77 | #include <arpa/nameser.h>
|
| 78 | #include <arpa/inet.h>
|
| 79 |
|
| 80 | #include <errno.h>
|
| 81 | #include <limits.h>
|
| 82 | #include <netdb.h>
|
| 83 | #include <resolv.h>
|
| 84 | #include <stdio.h>
|
| 85 | #include <stdlib.h>
|
| 86 | #include <string.h>
|
| 87 | #include <unistd.h>
|
| 88 | #include <ctype.h>
|
| 89 |
|
| 90 | #include "res_config.h"
|
| 91 |
|
| 92 | static int getnum_str(u_char **, u_char *);
|
| 93 | static int getword_str(char *, int, u_char **, u_char *);
|
| 94 |
|
| 95 | #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
|
| 96 |
|
| 97 | /*
|
| 98 | * Form update packets.
|
| 99 | * Returns the size of the resulting packet if no error
|
| 100 | * On error,
|
| 101 | * returns -1 if error in reading a word/number in rdata
|
| 102 | * portion for update packets
|
| 103 | * -2 if length of buffer passed is insufficient
|
| 104 | * -3 if zone section is not the first section in
|
| 105 | * the linked list, or section order has a problem
|
| 106 | * -4 on a number overflow
|
| 107 | * -5 unknown operation or no records
|
| 108 | */
|
| 109 | int
|
| 110 | res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) {
|
| 111 | ns_updrec *rrecp_start = rrecp_in;
|
| 112 | HEADER *hp;
|
| 113 | u_char *cp, *sp2, *startp, *endp;
|
| 114 | int n, i, soanum, multiline;
|
| 115 | ns_updrec *rrecp;
|
| 116 | struct in_addr ina;
|
| 117 | char buf2[MAXDNAME];
|
| 118 | int section, numrrs = 0, counts[ns_s_max];
|
| 119 | u_int16_t rtype, rclass;
|
| 120 | u_int32_t n1, rttl;
|
| 121 | u_char *dnptrs[20], **dpp, **lastdnptr;
|
| 122 |
|
| 123 | if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
|
| 124 | h_errno = NETDB_INTERNAL;
|
| 125 | return (-1);
|
| 126 | }
|
| 127 |
|
| 128 | /*
|
| 129 | * Initialize header fields.
|
| 130 | */
|
| 131 | if ((buf == NULL) || (buflen < HFIXEDSZ))
|
| 132 | return (-1);
|
| 133 | memset(buf, 0, HFIXEDSZ);
|
| 134 | hp = (HEADER *) buf;
|
| 135 | hp->id = htons(++_res.id);
|
| 136 | hp->opcode = ns_o_update;
|
| 137 | hp->rcode = NOERROR;
|
| 138 | cp = buf + HFIXEDSZ;
|
| 139 | buflen -= HFIXEDSZ;
|
| 140 | dpp = dnptrs;
|
| 141 | *dpp++ = buf;
|
| 142 | *dpp++ = NULL;
|
| 143 | lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
|
| 144 |
|
| 145 | if (rrecp_start == NULL)
|
| 146 | return (-5);
|
| 147 | else if (rrecp_start->r_section != S_ZONE)
|
| 148 | return (-3);
|
| 149 |
|
| 150 | memset(counts, 0, sizeof counts);
|
| 151 | for (rrecp = rrecp_start; rrecp; rrecp = rrecp->r_grpnext) {
|
| 152 | numrrs++;
|
| 153 | section = rrecp->r_section;
|
| 154 | if (section < 0 || section >= ns_s_max)
|
| 155 | return (-1);
|
| 156 | counts[section]++;
|
| 157 | for (i = section + 1; i < ns_s_max; i++)
|
| 158 | if (counts[i])
|
| 159 | return (-3);
|
| 160 | rtype = rrecp->r_type;
|
| 161 | rclass = rrecp->r_class;
|
| 162 | rttl = rrecp->r_ttl;
|
| 163 | /* overload class and type */
|
| 164 | if (section == S_PREREQ) {
|
| 165 | rttl = 0;
|
| 166 | switch (rrecp->r_opcode) {
|
| 167 | case YXDOMAIN:
|
| 168 | rclass = C_ANY;
|
| 169 | rtype = T_ANY;
|
| 170 | rrecp->r_size = 0;
|
| 171 | break;
|
| 172 | case NXDOMAIN:
|
| 173 | rclass = C_NONE;
|
| 174 | rtype = T_ANY;
|
| 175 | rrecp->r_size = 0;
|
| 176 | break;
|
| 177 | case NXRRSET:
|
| 178 | rclass = C_NONE;
|
| 179 | rrecp->r_size = 0;
|
| 180 | break;
|
| 181 | case YXRRSET:
|
| 182 | if (rrecp->r_size == 0)
|
| 183 | rclass = C_ANY;
|
| 184 | break;
|
| 185 | default:
|
| 186 | fprintf(stderr,
|
| 187 | "res_mkupdate: incorrect opcode: %d\n",
|
| 188 | rrecp->r_opcode);
|
| 189 | fflush(stderr);
|
| 190 | return (-1);
|
| 191 | }
|
| 192 | } else if (section == S_UPDATE) {
|
| 193 | switch (rrecp->r_opcode) {
|
| 194 | case DELETE:
|
| 195 | rclass = rrecp->r_size == 0 ? C_ANY : C_NONE;
|
| 196 | break;
|
| 197 | case ADD:
|
| 198 | break;
|
| 199 | default:
|
| 200 | fprintf(stderr,
|
| 201 | "res_mkupdate: incorrect opcode: %d\n",
|
| 202 | rrecp->r_opcode);
|
| 203 | fflush(stderr);
|
| 204 | return (-1);
|
| 205 | }
|
| 206 | }
|
| 207 |
|
| 208 | /*
|
| 209 | * XXX appending default domain to owner name is omitted,
|
| 210 | * fqdn must be provided
|
| 211 | */
|
| 212 | if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
|
| 213 | lastdnptr)) < 0)
|
| 214 | return (-1);
|
| 215 | cp += n;
|
| 216 | ShrinkBuffer(n + 2*INT16SZ);
|
| 217 | PUTSHORT(rtype, cp);
|
| 218 | PUTSHORT(rclass, cp);
|
| 219 | if (section == S_ZONE) {
|
| 220 | if (numrrs != 1 || rrecp->r_type != T_SOA)
|
| 221 | return (-3);
|
| 222 | continue;
|
| 223 | }
|
| 224 | ShrinkBuffer(INT32SZ + INT16SZ);
|
| 225 | PUTLONG(rttl, cp);
|
| 226 | sp2 = cp; /* save pointer to length byte */
|
| 227 | cp += INT16SZ;
|
| 228 | if (rrecp->r_size == 0) {
|
| 229 | if (section == S_UPDATE && rclass != C_ANY)
|
| 230 | return (-1);
|
| 231 | else {
|
| 232 | PUTSHORT(0, sp2);
|
| 233 | continue;
|
| 234 | }
|
| 235 | }
|
| 236 | startp = rrecp->r_data;
|
| 237 | endp = startp + rrecp->r_size - 1;
|
| 238 | /* XXX this should be done centrally. */
|
| 239 | switch (rrecp->r_type) {
|
| 240 | case T_A:
|
| 241 | if (!getword_str(buf2, sizeof buf2, &startp, endp))
|
| 242 | return (-1);
|
| 243 | if (!inet_aton(buf2, &ina))
|
| 244 | return (-1);
|
| 245 | n1 = ntohl(ina.s_addr);
|
| 246 | ShrinkBuffer(INT32SZ);
|
| 247 | PUTLONG(n1, cp);
|
| 248 | break;
|
| 249 | case T_CNAME:
|
| 250 | case T_MB:
|
| 251 | case T_MG:
|
| 252 | case T_MR:
|
| 253 | case T_NS:
|
| 254 | case T_PTR:
|
| 255 | if (!getword_str(buf2, sizeof buf2, &startp, endp))
|
| 256 | return (-1);
|
| 257 | n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
|
| 258 | if (n < 0)
|
| 259 | return (-1);
|
| 260 | cp += n;
|
| 261 | ShrinkBuffer(n);
|
| 262 | break;
|
| 263 | case T_MINFO:
|
| 264 | case T_SOA:
|
| 265 | case T_RP:
|
| 266 | for (i = 0; i < 2; i++) {
|
| 267 | if (!getword_str(buf2, sizeof buf2, &startp,
|
| 268 | endp))
|
| 269 | return (-1);
|
| 270 | n = dn_comp(buf2, cp, buflen,
|
| 271 | dnptrs, lastdnptr);
|
| 272 | if (n < 0)
|
| 273 | return (-1);
|
| 274 | cp += n;
|
| 275 | ShrinkBuffer(n);
|
| 276 | }
|
| 277 | if (rrecp->r_type == T_SOA) {
|
| 278 | ShrinkBuffer(5 * INT32SZ);
|
| 279 | while (isspace(*startp) || !*startp)
|
| 280 | startp++;
|
| 281 | if (*startp == '(') {
|
| 282 | multiline = 1;
|
| 283 | startp++;
|
| 284 | } else
|
| 285 | multiline = 0;
|
| 286 | /* serial, refresh, retry, expire, minimum */
|
| 287 | for (i = 0; i < 5; i++) {
|
| 288 | soanum = getnum_str(&startp, endp);
|
| 289 | if (soanum < 0)
|
| 290 | return (-1);
|
| 291 | PUTLONG(soanum, cp);
|
| 292 | }
|
| 293 | if (multiline) {
|
| 294 | while (isspace(*startp) || !*startp)
|
| 295 | startp++;
|
| 296 | if (*startp != ')')
|
| 297 | return (-1);
|
| 298 | }
|
| 299 | }
|
| 300 | break;
|
| 301 | case T_MX:
|
| 302 | case T_AFSDB:
|
| 303 | case T_RT:
|
| 304 | n = getnum_str(&startp, endp);
|
| 305 | if (n < 0)
|
| 306 | return (-1);
|
| 307 | PUTSHORT(n, cp);
|
| 308 | ShrinkBuffer(INT16SZ);
|
| 309 | if (!getword_str(buf2, sizeof buf2, &startp, endp))
|
| 310 | return (-1);
|
| 311 | n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
|
| 312 | if (n < 0)
|
| 313 | return (-1);
|
| 314 | cp += n;
|
| 315 | ShrinkBuffer(n);
|
| 316 | break;
|
| 317 | case T_PX:
|
| 318 | n = getnum_str(&startp, endp);
|
| 319 | if (n < 0)
|
| 320 | return (-1);
|
| 321 | PUTSHORT(n, cp);
|
| 322 | ShrinkBuffer(INT16SZ);
|
| 323 | for (i = 0; i < 2; i++) {
|
| 324 | if (!getword_str(buf2, sizeof buf2, &startp,
|
| 325 | endp))
|
| 326 | return (-1);
|
| 327 | n = dn_comp(buf2, cp, buflen, dnptrs,
|
| 328 | lastdnptr);
|
| 329 | if (n < 0)
|
| 330 | return (-1);
|
| 331 | cp += n;
|
| 332 | ShrinkBuffer(n);
|
| 333 | }
|
| 334 | break;
|
| 335 | case T_WKS:
|
| 336 | case T_HINFO:
|
| 337 | case T_TXT:
|
| 338 | case T_X25:
|
| 339 | case T_ISDN:
|
| 340 | case T_NSAP:
|
| 341 | case T_LOC:
|
| 342 | /* XXX - more fine tuning needed here */
|
| 343 | ShrinkBuffer(rrecp->r_size);
|
| 344 | memcpy(cp, rrecp->r_data, rrecp->r_size);
|
| 345 | cp += rrecp->r_size;
|
| 346 | break;
|
| 347 | default:
|
| 348 | return (-1);
|
| 349 | } /*switch*/
|
| 350 | n = (u_int16_t)((cp - sp2) - INT16SZ);
|
| 351 | PUTSHORT(n, sp2);
|
| 352 | } /*for*/
|
| 353 |
|
| 354 | hp->qdcount = htons(counts[0]);
|
| 355 | hp->ancount = htons(counts[1]);
|
| 356 | hp->nscount = htons(counts[2]);
|
| 357 | hp->arcount = htons(counts[3]);
|
| 358 | return ((int)(cp - buf));
|
| 359 | }
|
| 360 |
|
| 361 | /*
|
| 362 | * Get a whitespace delimited word from a string (not file)
|
| 363 | * into buf. modify the start pointer to point after the
|
| 364 | * word in the string.
|
| 365 | */
|
| 366 | static int
|
| 367 | getword_str(char *buf, int size, u_char **startpp, u_char *endp) {
|
| 368 | char *cp;
|
| 369 | int c;
|
| 370 |
|
| 371 | for (cp = buf; *startpp <= endp; ) {
|
| 372 | c = **startpp;
|
| 373 | if (isspace(c) || c == '\0') {
|
| 374 | if (cp != buf) /* trailing whitespace */
|
| 375 | break;
|
| 376 | else { /* leading whitespace */
|
| 377 | (*startpp)++;
|
| 378 | continue;
|
| 379 | }
|
| 380 | }
|
| 381 | (*startpp)++;
|
| 382 | if (cp >= buf+size-1)
|
| 383 | break;
|
| 384 | *cp++ = (u_char)c;
|
| 385 | }
|
| 386 | *cp = '\0';
|
| 387 | return (cp != buf);
|
| 388 | }
|
| 389 |
|
| 390 | /*
|
| 391 | * Get a whitespace delimited number from a string (not file) into buf
|
| 392 | * update the start pointer to point after the number in the string.
|
| 393 | */
|
| 394 | static int
|
| 395 | getnum_str(u_char **startpp, u_char *endp) {
|
| 396 | int c;
|
| 397 | int n;
|
| 398 | int seendigit = 0;
|
| 399 | int m = 0;
|
| 400 |
|
| 401 | for (n = 0; *startpp <= endp; ) {
|
| 402 | c = **startpp;
|
| 403 | if (isspace(c) || c == '\0') {
|
| 404 | if (seendigit) /* trailing whitespace */
|
| 405 | break;
|
| 406 | else { /* leading whitespace */
|
| 407 | (*startpp)++;
|
| 408 | continue;
|
| 409 | }
|
| 410 | }
|
| 411 | if (c == ';') {
|
| 412 | while ((*startpp <= endp) &&
|
| 413 | ((c = **startpp) != '\n'))
|
| 414 | (*startpp)++;
|
| 415 | if (seendigit)
|
| 416 | break;
|
| 417 | continue;
|
| 418 | }
|
| 419 | if (!isdigit(c)) {
|
| 420 | if (c == ')' && seendigit) {
|
| 421 | (*startpp)--;
|
| 422 | break;
|
| 423 | }
|
| 424 | return (-1);
|
| 425 | }
|
| 426 | (*startpp)++;
|
| 427 | n = n * 10 + (c - '0');
|
| 428 | seendigit = 1;
|
| 429 | }
|
| 430 | return (n + m);
|
| 431 | }
|
| 432 |
|
| 433 | /*
|
| 434 | * Allocate a resource record buffer & save rr info.
|
| 435 | */
|
| 436 | ns_updrec *
|
| 437 | res_mkupdrec(int section, const char *dname,
|
| 438 | u_int class, u_int type, u_long ttl) {
|
| 439 | ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
|
| 440 |
|
| 441 | if (!rrecp || !(rrecp->r_dname = strdup(dname)))
|
| 442 | return (NULL);
|
| 443 | rrecp->r_class = (u_int16_t)class;
|
| 444 | rrecp->r_type = (u_int16_t)type;
|
| 445 | rrecp->r_ttl = (u_int32_t)ttl;
|
| 446 | rrecp->r_section = (u_int8_t)section;
|
| 447 | return (rrecp);
|
| 448 | }
|
| 449 |
|
| 450 | /*
|
| 451 | * Free a resource record buffer created by res_mkupdrec.
|
| 452 | */
|
| 453 | void
|
| 454 | res_freeupdrec(ns_updrec *rrecp) {
|
| 455 | /* Note: freeing r_dp is the caller's responsibility. */
|
| 456 | if (rrecp->r_dname != NULL)
|
| 457 | free(rrecp->r_dname);
|
| 458 | free(rrecp);
|
| 459 | }
|