source: rtems/cpukit/libnetworking/libc/res_update.c @ 9d647dfc

4.104.114.84.95
Last change on this file since 9d647dfc was ff0f694d, checked in by Joel Sherrill <joel.sherrill@…>, on 08/20/98 at 21:47:37

Fixed many warnings.

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