Fixes stat() #include
[akaros.git] / user / ndblib / dnsquery.c
1 /* 
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9 #include <stdlib.h>
10
11 #include <stdio.h>
12 #include <parlib.h>
13 #include <unistd.h>
14 #include <signal.h>
15 #include <fcntl.h>
16 #include <iplib.h>
17 #include <ndb.h>
18
19 static void nstrcpy(char*, char*, int);
20 static void mkptrname(char*, char*, int);
21 static struct ndbtuple *doquery(int, char *dn, char *type);
22
23 /*
24  *  search for a tuple that has the given 'attr=val' and also 'rattr=x'.
25  *  copy 'x' into 'buf' and return the whole tuple.
26  *
27  *  return 0 if not found.
28  */
29 struct ndbtuple*
30 dnsquery(char *net, char *val, char *type)
31 {
32         char rip[128];
33         char *p;
34         struct ndbtuple *t;
35         int fd;
36
37         /* if the address is V4 or V6 null address, give up early */
38         if(strcmp(val, "::") == 0 || strcmp(val, "0.0.0.0") == 0)
39                 return NULL;
40
41         if(net == NULL)
42                 net = "/net";
43         snprintf(rip, sizeof(rip), "%s/dns", net);
44         fd = open(rip, O_RDWR);
45         if(fd < 0){
46                 if(strcmp(net, "/net") == 0)
47                         snprintf(rip, sizeof(rip), "/srv/dns");
48                 else {
49                         snprintf(rip, sizeof(rip), "/srv/dns%s", net);
50                         p = strrchr(rip, '/');
51                         *p = '_';
52                 }
53                 fd = open(rip, O_RDWR);
54                 if(fd < 0)
55                         return NULL;
56 #if 0
57                 if(mount(fd, -1, net, MBEFORE, "") < 0){
58                         close(fd);
59                         return NULL;
60                 }
61 #else
62 #define MBEFORE 1
63 #define NOAUTHFD -1
64                 int ret;
65                 ret = syscall(SYS_nmount, fd, NOAUTHFD, net, MBEFORE, "");
66                 if (ret < 0){
67                         close(fd);
68                         return NULL;
69                 }
70 #endif
71                 /* fd is now closed */
72                 snprintf(rip, sizeof(rip), "%s/dns", net);
73                 fd = open(rip, O_RDWR);
74                 if(fd < 0)
75                         return NULL;
76         }
77
78         /* zero out the error string */
79         werrstr("");
80
81         /* if this is a reverse lookup, first lookup the domain name */
82         if(strcmp(type, "ptr") == 0){
83                 mkptrname(val, rip, sizeof rip);
84                 t = doquery(fd, rip, "ptr");
85         } else
86                 t = doquery(fd, val, type);
87
88         /*
89          * TODO: make fd static and keep it open to reduce 9P traffic
90          * walking to /net*^/dns.  Must be prepared to re-open it on error.
91          */
92         close(fd);
93         ndbsetmalloctag(t, getcallerpc(&net));
94         return t;
95 }
96
97 /*
98  *  convert address into a reverse lookup address
99  */
100 static void
101 mkptrname(char *ip, char *rip, int rlen)
102 {
103         char buf[128];
104         char *p, *np;
105         int len;
106
107         if(strstr(ip, "in-addr.arpa") || strstr(ip, "IN-ADDR.ARPA")){
108                 nstrcpy(rip, ip, rlen);
109                 return;
110         }
111
112         nstrcpy(buf, ip, sizeof buf);
113         for(p = buf; *p; p++)
114                 ;
115         *p = '.';
116         np = rip;
117         len = 0;
118         while(p >= buf){
119                 len++;
120                 p--;
121                 if(*p == '.'){
122                         memmove(np, p+1, len);
123                         np += len;
124                         len = 0;
125                 }
126         }
127         memmove(np, p+1, len);
128         np += len;
129         strcpy(np, "in-addr.arpa");
130 }
131
132 static void
133 nstrcpy(char *to, char *from, int len)
134 {
135         strncpy(to, from, len);
136         to[len-1] = 0;
137 }
138
139 static struct ndbtuple*
140 doquery(int fd, char *dn, char *type)
141 {
142         char buf[1024];
143         int n;
144         struct ndbtuple *t, *first, *last;
145
146         lseek(fd, 0, 0);
147         snprintf(buf, sizeof(buf), "!%s %s", dn, type);
148         if(write(fd, buf, strlen(buf)) < 0)
149                 return NULL;
150                 
151         lseek(fd, 0, 0);
152
153         first = last = NULL;
154         
155         for(;;){
156                 n = read(fd, buf, sizeof(buf)-2);
157                 if(n <= 0)
158                         break;
159                 if(buf[n-1] != '\n')
160                         buf[n++] = '\n';        /* ndbparsline needs a trailing new line */
161                 buf[n] = 0;
162
163                 /* check for the error condition */
164                 if(buf[0] == '!'){
165                         werrstr("%s", buf+1);
166                         return NULL;
167                 }
168
169                 t = _ndbparseline(buf);
170                 if(t != NULL){
171                         if(first)
172                                 last->entry = t;
173                         else
174                                 first = t;
175                         last = t;
176
177                         while(last->entry)
178                                 last = last->entry;
179                 }
180         }
181
182         ndbsetmalloctag(first, getcallerpc(&fd));
183         return first;
184 }