source: rtems/cpukit/libnetworking/libc/res_update.c @ 39f13cb

4.104.115
Last change on this file since 39f13cb was 39f13cb, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/27/10 at 04:00:53

Add HAVE_STRINGS_H for better POSIX compliance.

  • Property mode set to 100644
File size: 13.8 KB
Line 
1/*
2 * Copyright (c) 1996 by Internet Software Consortium.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15 * SOFTWARE.
16 */
17
18#if HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22/*
23 * Based on the Dynamic DNS reference implementation by Viraj Bais
24 * <viraj_bais@ccm.fm.intel.com>
25 */
26
27#include <sys/param.h>
28#include <sys/socket.h>
29#include <sys/time.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32#include <arpa/nameser.h>
33#include <errno.h>
34#include <limits.h>
35#include <netdb.h>
36#include <resolv.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#ifdef HAVE_STRINGS_H
41#include <strings.h>
42#endif
43
44/*
45 * Separate a linked list of records into groups so that all records
46 * in a group will belong to a single zone on the nameserver.
47 * Create a dynamic update packet for each zone and send it to the
48 * nameservers for that zone, and await answer.
49 * Abort if error occurs in updating any zone.
50 * Return the number of zones updated on success, < 0 on error.
51 *
52 * On error, caller must deal with the unsynchronized zones
53 * eg. an A record might have been successfully added to the forward
54 * zone but the corresponding PTR record would be missing if error
55 * was encountered while updating the reverse zone.
56 */
57
58#define NSMAX 16
59
60struct ns1 {
61        char nsname[MAXDNAME];
62        struct in_addr nsaddr1;
63};
64
65struct zonegrp {
66        char            z_origin[MAXDNAME];
67        int16_t         z_class;
68        char            z_soardata[MAXDNAME + 5 * INT32SZ];
69        struct ns1      z_ns[NSMAX];
70        int             z_nscount;
71        ns_updrec *     z_rr;
72        struct zonegrp *z_next;
73};
74
75
76int
77res_update(ns_updrec *rrecp_in) {
78        ns_updrec *rrecp, *tmprrecp;
79        u_char buf[PACKETSZ], answer[PACKETSZ], packet[2*PACKETSZ];
80        char name[MAXDNAME], zname[MAXDNAME], primary[MAXDNAME],
81             mailaddr[MAXDNAME];
82        u_char soardata[2*MAXCDNAME+5*INT32SZ];
83        char *dname, *svdname, *cp1, *target;
84        u_char *cp, *eom;
85        HEADER *hp = (HEADER *) answer;
86        struct zonegrp *zptr = NULL, *tmpzptr, *prevzptr, *zgrp_start = NULL;
87        int i, j, k = 0, n, ancount, nscount, arcount, rcode, rdatasize,
88            newgroup, done, myzone, seen_before, numzones = 0;
89        u_int16_t dlen, class, qclass, type, qtype;
90        u_int32_t ttl;
91
92        if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
93                h_errno = NETDB_INTERNAL;
94                return (-1);
95        }
96
97        for (rrecp = rrecp_in; rrecp; rrecp = rrecp->r_next) {
98                dname = rrecp->r_dname;
99                n = strlen(dname);
100                if (dname[n-1] == '.')
101                        dname[n-1] = '\0';
102                qtype = T_SOA;
103                qclass = rrecp->r_class;
104                done = 0;
105                seen_before = 0;
106
107                while (!done && dname) {
108                    if (qtype == T_SOA) {
109                        for (tmpzptr = zgrp_start;
110                             tmpzptr && !seen_before;
111                             tmpzptr = tmpzptr->z_next) {
112                                if (strcasecmp(dname,
113                                               tmpzptr->z_origin) == 0 &&
114                                    tmpzptr->z_class == qclass)
115                                        seen_before++;
116                                for (tmprrecp = tmpzptr->z_rr;
117                                     tmprrecp && !seen_before;
118                                     tmprrecp = tmprrecp->r_grpnext)
119                                if (strcasecmp(dname, tmprrecp->r_dname) == 0
120                                    && tmprrecp->r_class == qclass) {
121                                        seen_before++;
122                                        break;
123                                }
124                                if (seen_before) {
125                                        /*
126                                         * Append to the end of
127                                         * current group.
128                                         */
129                                        for (tmprrecp = tmpzptr->z_rr;
130                                             tmprrecp->r_grpnext;
131                                             tmprrecp = tmprrecp->r_grpnext)
132                                                (void)NULL;
133                                        tmprrecp->r_grpnext = rrecp;
134                                        rrecp->r_grpnext = NULL;
135                                        done = 1;
136                                        break;
137                                }
138                        }
139                } else if (qtype == T_A) {
140                    for (tmpzptr = zgrp_start;
141                         tmpzptr && !done;
142                         tmpzptr = tmpzptr->z_next)
143                            for (i = 0; i < tmpzptr->z_nscount; i++)
144                                if (tmpzptr->z_class == qclass &&
145                                    strcasecmp(tmpzptr->z_ns[i].nsname,
146                                               dname) == 0 &&
147                                    tmpzptr->z_ns[i].nsaddr1.s_addr != 0) {
148                                        zptr->z_ns[k].nsaddr1.s_addr =
149                                         tmpzptr->z_ns[i].nsaddr1.s_addr;
150                                        done = 1;
151                                        break;
152                                }
153                }
154                if (done)
155                    break;
156                n = res_mkquery(QUERY, dname, qclass, qtype, NULL,
157                                0, NULL, buf, sizeof buf);
158                if (n <= 0) {
159                    fprintf(stderr, "res_update: mkquery failed\n");
160                    return (n);
161                }
162                n = res_send(buf, n, answer, sizeof answer);
163                if (n < 0) {
164                    fprintf(stderr, "res_update: send error for %s\n",
165                            rrecp->r_dname);
166                    return (n);
167                }
168                if (n < HFIXEDSZ)
169                        return (-1);
170                ancount = ntohs(hp->ancount);
171                nscount = ntohs(hp->nscount);
172                arcount = ntohs(hp->arcount);
173                rcode = hp->rcode;
174                cp = answer + HFIXEDSZ;
175                eom = answer + n;
176                /* skip the question section */
177                n = dn_skipname(cp, eom);
178                if (n < 0 || cp + n + 2 * INT16SZ > eom)
179                        return (-1);
180                cp += n + 2 * INT16SZ;
181
182                if (qtype == T_SOA) {
183                    if (ancount == 0 && nscount == 0 && arcount == 0) {
184                        /*
185                         * if (rcode == NOERROR) then the dname exists but
186                         * has no soa record associated with it.
187                         * if (rcode == NXDOMAIN) then the dname does not
188                         * exist and the server is replying out of NCACHE.
189                         * in either case, proceed with the next try
190                         */
191                        dname = strchr(dname, '.');
192                        if (dname != NULL)
193                                dname++;
194                        continue;
195                    } else if ((rcode == NOERROR || rcode == NXDOMAIN) &&
196                               ancount == 0 &&
197                               nscount == 1 && arcount == 0) {
198                        /*
199                         * name/data does not exist, soa record supplied in the
200                         * authority section
201                         */
202                        /* authority section must contain the soa record */
203                        if ((n = dn_expand(answer, eom, cp, zname,
204                                        sizeof zname)) < 0)
205                            return (n);
206                        cp += n;
207                        if (cp + 2 * INT16SZ > eom)
208                                return (-1);
209                        GETSHORT(type, cp);
210                        GETSHORT(class, cp);
211                        if (type != T_SOA || class != qclass) {
212                            fprintf(stderr, "unknown answer\n");
213                            return (-1);
214                        }
215                        myzone = 0;
216                        svdname = dname;
217                        while (dname)
218                            if (strcasecmp(dname, zname) == 0) {
219                                myzone = 1;
220                                break;
221                            } else if ((dname = strchr(dname, '.')) != NULL)
222                                dname++;
223                        if (!myzone) {
224                            dname = strchr(svdname, '.');
225                            if (dname != NULL)
226                                dname++;
227                            continue;
228                        }
229                        nscount = 0;
230                        /* fallthrough */
231                    } else if (rcode == NOERROR && ancount == 1) {
232                        /*
233                         * found the zone name
234                         * new servers will supply NS records for the zone
235                         * in authority section and A records for those
236                         * nameservers in the additional section
237                         * older servers have to be explicitly queried for
238                         * NS records for the zone
239                         */
240                        /* answer section must contain the soa record */
241                        if ((n = dn_expand(answer, eom, cp, zname,
242                                           sizeof zname)) < 0)
243                                return (n);
244                        else
245                                cp += n;
246                        if (cp + 2 * INT16SZ > eom)
247                                return (-1);
248                        GETSHORT(type, cp);
249                        GETSHORT(class, cp);
250                        if (type == T_CNAME) {
251                                dname = strchr(dname, '.');
252                                if (dname != NULL)
253                                        dname++;
254                                continue;
255                        }
256                        if (strcasecmp(dname, zname) != 0 ||
257                            type != T_SOA ||
258                            class != rrecp->r_class) {
259                                fprintf(stderr, "unknown answer\n");
260                                return (-1);
261                        }
262                        /* FALLTHROUGH */
263                    } else {
264                        fprintf(stderr,
265                "unknown response: ans=%d, auth=%d, add=%d, rcode=%d\n",
266                                ancount, nscount, arcount, hp->rcode);
267                        return (-1);
268                    }
269                    if (cp + INT32SZ + INT16SZ > eom)
270                            return (-1);
271                    /* continue processing the soa record */
272                    GETLONG(ttl, cp);
273                    GETSHORT(dlen, cp);
274                    if (cp + dlen > eom)
275                            return (-1);
276                    newgroup = 1;
277                    zptr = zgrp_start;
278                    prevzptr = NULL;
279                    while (zptr) {
280                        if (strcasecmp(zname, zptr->z_origin) == 0 &&
281                            type == T_SOA && class == qclass) {
282                                newgroup = 0;
283                                break;
284                        }
285                        prevzptr = zptr;
286                        zptr = zptr->z_next;
287                    }
288                    if (!newgroup) {
289                        for (tmprrecp = zptr->z_rr;
290                             tmprrecp->r_grpnext;
291                             tmprrecp = tmprrecp->r_grpnext)
292                                    ;
293                        tmprrecp->r_grpnext = rrecp;
294                        rrecp->r_grpnext = NULL;
295                        done = 1;
296                        cp += dlen;
297                        break;
298                    } else {
299                        if ((n = dn_expand(answer, eom, cp, primary,
300                                           sizeof primary)) < 0)
301                            return (n);
302                        cp += n;
303                        /*
304                         * We don't have to bounds check here because the
305                         * next use of 'cp' is in dn_expand().
306                         */
307                        cp1 = (char *)soardata;
308                        strcpy(cp1, primary);
309                        cp1 += strlen(cp1) + 1;
310                        if ((n = dn_expand(answer, eom, cp, mailaddr,
311                                           sizeof mailaddr)) < 0)
312                            return (n);
313                        cp += n;
314                        strcpy(cp1, mailaddr);
315                        cp1 += strlen(cp1) + 1;
316                        if (cp + 5*INT32SZ > eom)
317                                return (-1);
318                        memcpy(cp1, cp, 5*INT32SZ);
319                        cp += 5*INT32SZ;
320                        cp1 += 5*INT32SZ;
321                        rdatasize = (u_char *)cp1 - soardata;
322                        zptr = calloc(1, sizeof(struct zonegrp));
323                        if (zptr == NULL)
324                            return (-1);
325                        if (zgrp_start == NULL)
326                            zgrp_start = zptr;
327                        else
328                            prevzptr->z_next = zptr;
329                        zptr->z_rr = rrecp;
330                        rrecp->r_grpnext = NULL;
331                        strcpy(zptr->z_origin, zname);
332                        zptr->z_class = class;
333                        memcpy(zptr->z_soardata, soardata, rdatasize);
334                        /* fallthrough to process NS and A records */
335                    }
336                } else if (qtype == T_NS) {
337                    if (rcode == NOERROR && ancount > 0) {
338                        strcpy(zname, dname);
339                        for (zptr = zgrp_start; zptr; zptr = zptr->z_next) {
340                            if (strcasecmp(zname, zptr->z_origin) == 0)
341                                break;
342                        }
343                        if (zptr == NULL)
344                            /* should not happen */
345                            return (-1);
346                        if (nscount > 0) {
347                            /*
348                             * answer and authority sections contain
349                             * the same information, skip answer section
350                             */
351                            for (j = 0; j < ancount; j++) {
352                                n = dn_skipname(cp, eom);
353                                if (n < 0)
354                                        return (-1);
355                                n += 2*INT16SZ + INT32SZ;
356                                if (cp + n + INT16SZ > eom)
357                                        return (-1);
358                                cp += n;
359                                GETSHORT(dlen, cp);
360                                cp += dlen;
361                            }
362                        } else
363                            nscount = ancount;
364                        /* fallthrough to process NS and A records */
365                    } else {
366                        fprintf(stderr, "cannot determine nameservers for %s:\
367ans=%d, auth=%d, add=%d, rcode=%d\n",
368                                dname, ancount, nscount, arcount, hp->rcode);
369                        return (-1);
370                    }
371                } else if (qtype == T_A) {
372                    if (rcode == NOERROR && ancount > 0) {
373                        arcount = ancount;
374                        ancount = nscount = 0;
375                        /* fallthrough to process A records */
376                    } else {
377                        fprintf(stderr, "cannot determine address for %s:\
378ans=%d, auth=%d, add=%d, rcode=%d\n",
379                                dname, ancount, nscount, arcount, hp->rcode);
380                        return (-1);
381                    }
382                }
383                /* process NS records for the zone */
384                j = 0;
385                for (i = 0; i < nscount; i++) {
386                    if ((n = dn_expand(answer, eom, cp, name,
387                                        sizeof name)) < 0)
388                        return (n);
389                    cp += n;
390                    if (cp + 3 * INT16SZ + INT32SZ > eom)
391                            return (-1);
392                    GETSHORT(type, cp);
393                    GETSHORT(class, cp);
394                    GETLONG(ttl, cp);
395                    GETSHORT(dlen, cp);
396                    if (cp + dlen > eom)
397                        return (-1);
398                    if (strcasecmp(name, zname) == 0 &&
399                        type == T_NS && class == qclass) {
400                                if ((n = dn_expand(answer, eom, cp,
401                                                   name, sizeof name)) < 0)
402                                        return (n);
403                            target = zptr->z_ns[j++].nsname;
404                            strcpy(target, name);
405                    }
406                    cp += dlen;
407                }
408                if (zptr->z_nscount == 0)
409                    zptr->z_nscount = j;
410                /* get addresses for the nameservers */
411                for (i = 0; i < arcount; i++) {
412                    if ((n = dn_expand(answer, eom, cp, name,
413                                        sizeof name)) < 0)
414                        return (n);
415                    cp += n;
416                    if (cp + 3 * INT16SZ + INT32SZ > eom)
417                        return (-1);
418                    GETSHORT(type, cp);
419                    GETSHORT(class, cp);
420                    GETLONG(ttl, cp);
421                    GETSHORT(dlen, cp);
422                    if (cp + dlen > eom)
423                            return (-1);
424                    if (type == T_A && dlen == INT32SZ && class == qclass) {
425                        for (j = 0; j < zptr->z_nscount; j++)
426                            if (strcasecmp(name, zptr->z_ns[j].nsname) == 0) {
427                                memcpy(&zptr->z_ns[j].nsaddr1.s_addr, cp,
428                                       INT32SZ);
429                                break;
430                            }
431                    }
432                    cp += dlen;
433                }
434                if (zptr->z_nscount == 0) {
435                    dname = zname;
436                    qtype = T_NS;
437                    continue;
438                }
439                done = 1;
440                for (k = 0; k < zptr->z_nscount; k++)
441                    if (zptr->z_ns[k].nsaddr1.s_addr == 0) {
442                        done = 0;
443                        dname = zptr->z_ns[k].nsname;
444                        qtype = T_A;
445                    }
446
447            } /* while */
448        }
449
450        _res.options |= RES_DEBUG;
451        for (zptr = zgrp_start; zptr; zptr = zptr->z_next) {
452
453                /* append zone section */
454                rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
455                                     zptr->z_class, ns_t_soa, 0);
456                if (rrecp == NULL) {
457                        fprintf(stderr, "saverrec error\n");
458                        fflush(stderr);
459                        return (-1);
460                }
461                rrecp->r_grpnext = zptr->z_rr;
462                zptr->z_rr = rrecp;
463
464                n = res_mkupdate(zptr->z_rr, packet, sizeof packet);
465                if (n < 0) {
466                        fprintf(stderr, "res_mkupdate error\n");
467                        fflush(stderr);
468                        return (-1);
469                } else
470                        fprintf(stdout, "res_mkupdate: packet size = %d\n", n);
471
472                /*
473                 * Override the list of NS records from res_init() with
474                 * the authoritative nameservers for the zone being updated.
475                 * Sort primary to be the first in the list of nameservers.
476                 */
477                for (i = 0; i < zptr->z_nscount; i++) {
478                        if (strcasecmp(zptr->z_ns[i].nsname,
479                                       zptr->z_soardata) == 0) {
480                                struct in_addr tmpaddr;
481
482                                if (i != 0) {
483                                        strcpy(zptr->z_ns[i].nsname,
484                                               zptr->z_ns[0].nsname);
485                                        strcpy(zptr->z_ns[0].nsname,
486                                               zptr->z_soardata);
487                                        tmpaddr = zptr->z_ns[i].nsaddr1;
488                                        zptr->z_ns[i].nsaddr1 =
489                                                zptr->z_ns[0].nsaddr1;
490                                        zptr->z_ns[0].nsaddr1 = tmpaddr;
491                                }
492                                break;
493                        }
494                }
495                for (i = 0; i < MAXNS; i++) {
496                        _res.nsaddr_list[i].sin_addr = zptr->z_ns[i].nsaddr1;
497                        _res.nsaddr_list[i].sin_family = AF_INET;
498                        _res.nsaddr_list[i].sin_port = htons(NAMESERVER_PORT);
499                }
500                _res.nscount = (zptr->z_nscount < MAXNS) ?
501                                        zptr->z_nscount : MAXNS;
502                n = res_send(packet, n, answer, sizeof(answer));
503                if (n < 0) {
504                        fprintf(stderr, "res_send: send error, n=%d\n", n);
505                        break;
506                } else
507                        numzones++;
508        }
509
510        /* free malloc'ed memory */
511        while(zgrp_start) {
512                zptr = zgrp_start;
513                zgrp_start = zgrp_start->z_next;
514                res_freeupdrec(zptr->z_rr);  /* Zone section we allocated. */
515                free((char *)zptr);
516        }
517
518        return (numzones);
519}
Note: See TracBrowser for help on using the repository browser.