ndbipinfo.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <ip.h>
  5. #include <ndb.h>
  6. typedef struct Attr Attr;
  7. struct Attr
  8. {
  9. Attr *next;
  10. int addronly;
  11. char *attr;
  12. Ndbtuple *first;
  13. Ndbtuple *last;
  14. int masklen;
  15. };
  16. #ifdef DEBUGGING
  17. static void
  18. prtuple(char *tag, Ndbtuple *t)
  19. {
  20. print("%s tag\n\t", tag);
  21. for(; t != nil; t = t->entry){
  22. print("%s=%s ", t->attr, t->val);
  23. if(t->entry != t->line){
  24. if(t->entry != nil)
  25. print("\n\t");
  26. else
  27. print("\n");
  28. }
  29. }
  30. }
  31. #endif DEBUGGING
  32. /*
  33. * reorder the tuple to put x's line first in the entry
  34. */
  35. static Ndbtuple*
  36. reorder(Ndbtuple *t, Ndbtuple *x)
  37. {
  38. Ndbtuple *nt;
  39. Ndbtuple *last, *prev;
  40. /* if x is first, we're done */
  41. if(x == t)
  42. return t;
  43. /* find end of x's line */
  44. for(last = x; last->line == last->entry; last = last->line)
  45. ;
  46. /* rotate to make this line first */
  47. if(last->line != t){
  48. /* detach this line and everything after it from the entry */
  49. for(nt = t; nt->entry != last->line; nt = nt->entry)
  50. ;
  51. nt->entry = nil;
  52. /* switch */
  53. for(nt = last; nt->entry != nil; nt = nt->entry)
  54. ;
  55. nt->entry = t;
  56. }
  57. /* rotate line to make x first */
  58. if(x != last->line){
  59. /* find entry before x */
  60. for(prev = last; prev->line != x; prev = prev->line);
  61. ;
  62. /* detach line */
  63. nt = last->entry;
  64. last->entry = last->line;
  65. /* reattach */
  66. prev->entry = nt;
  67. }
  68. return x;
  69. }
  70. /*
  71. * lookup an ip addresses
  72. */
  73. static Ndbtuple*
  74. toipaddr(Ndb *db, Ndbtuple *t)
  75. {
  76. Ndbtuple *xt, *nt, **l;
  77. char buf[Ndbvlen];
  78. Ndbs s;
  79. char *attr;
  80. attr = ipattr(t->val);
  81. if(strcmp(attr, "ip") == 0)
  82. return t;
  83. nt = ndbgetval(db, &s, attr, t->val, "ip", buf);
  84. if(nt == nil)
  85. return 0;
  86. nt = reorder(nt, s.t);
  87. /* throw out non ip twoples */
  88. l = &nt;
  89. while(*l != nil){
  90. xt = *l;
  91. if(strcmp(xt->attr, "ip") != 0){
  92. /* unlink */
  93. *l = xt->entry;
  94. xt->entry = nil;
  95. /* free */
  96. ndbfree(xt);
  97. continue;
  98. }
  99. strcpy(xt->attr, t->attr);
  100. l = &xt->entry;
  101. }
  102. ndbfree(t);
  103. return nt;
  104. }
  105. /*
  106. * Mine the entry for the desired attributes. Longer masks
  107. * take priority.
  108. */
  109. static Ndbtuple*
  110. mine(Ndb *db, Ndbtuple *t, Attr *a, int masklen, int *needed)
  111. {
  112. Ndbtuple **l, *nt;
  113. for(; a != nil; a = a->next){
  114. for(l = &t; *l != nil;){
  115. nt = *l;
  116. if(strcmp(a->attr, nt->attr) != 0){
  117. l = &nt->entry;
  118. continue;
  119. }
  120. if(a->first){
  121. /* longer masks replace shorter */
  122. if(masklen > a->masklen){
  123. ndbfree(a->first);
  124. a->first = nil;
  125. a->last = nil;
  126. (*needed)++;
  127. } else if(a->masklen > masklen) {
  128. l = &nt->entry;
  129. continue;
  130. }
  131. }
  132. /* unchain tuple from t */
  133. *l = nt->entry;
  134. nt->entry = nil;
  135. if(a->addronly)
  136. nt = toipaddr(db, nt);
  137. if(nt == nil)
  138. continue;
  139. /* chain tuple into the Attr */
  140. if(a->last)
  141. a->last->entry = nt;
  142. else
  143. a->first = nt;
  144. while(nt->entry)
  145. nt = nt->entry;
  146. a->last = nt;
  147. a->masklen = masklen;
  148. (*needed)--;
  149. }
  150. }
  151. return t;
  152. }
  153. static int
  154. prefixlen(uchar *ip)
  155. {
  156. int y, i;
  157. for(y = IPaddrlen-1; y >= 0; y--)
  158. for(i = 8; i > 0; i--)
  159. if(ip[y] & (1<<(8-i)))
  160. return y*8 + i;
  161. return 0;
  162. }
  163. /*
  164. * look for all networks whose masks are shorter than lastlen
  165. * and whose IP address matches net.
  166. */
  167. static void
  168. subnet(Ndb *db, uchar *net, Attr *a, int prefix, int *needed)
  169. {
  170. Ndbs s;
  171. Ndbtuple *t;
  172. char netstr[Ndbvlen];
  173. char maskstr[Ndbvlen];
  174. uchar mask[IPaddrlen];
  175. int masklen;
  176. sprint(netstr, "%I", net);
  177. t = ndbsearch(db, &s, "ip", netstr);
  178. while(t != nil){
  179. if(ndblookval(t, t, "ipnet", maskstr) != nil){
  180. if(ndblookval(t, t, "ipmask", maskstr))
  181. parseipmask(mask, maskstr);
  182. else
  183. ipmove(mask, defmask(net));
  184. masklen = prefixlen(mask);
  185. if(masklen <= prefix)
  186. t = mine(db, t, a, masklen, needed);
  187. }
  188. ndbfree(t);
  189. t = ndbsnext(&s, "ip", netstr);
  190. }
  191. }
  192. /*
  193. * fill in all the requested attributes for a system.
  194. * if the system's entry doesn't have all required,
  195. * walk through successively more inclusive networks
  196. * for inherited attributes.
  197. */
  198. Ndbtuple*
  199. ndbipinfo(Ndb *db, char *attr, char *val, char **alist, int n)
  200. {
  201. Ndbtuple *t, *nt, **lt;
  202. Ndbs s;
  203. char *p;
  204. Attr *a, *list, **l;
  205. int i, needed;
  206. char ipstr[Ndbvlen];
  207. uchar ip[IPaddrlen];
  208. uchar net[IPaddrlen];
  209. int prefix, smallestprefix;
  210. /* just in case */
  211. fmtinstall('I', eipfmt);
  212. fmtinstall('M', eipfmt);
  213. /* get needed attributes */
  214. needed = 0;
  215. l = &list;
  216. for(i = 0; i < n; i++){
  217. p = *alist++;
  218. if(p == nil)
  219. break;
  220. a = mallocz(sizeof(*a), 1);
  221. if(a == nil)
  222. break;
  223. if(*p == '@'){
  224. a->addronly = 1;
  225. p++;
  226. }
  227. a->attr = p;
  228. *l = a;
  229. l = &(*l)->next;
  230. needed++;
  231. }
  232. /*
  233. * first look for a matching entry with an ip address
  234. */
  235. t = ndbgetval(db, &s, attr, val, "ip", ipstr);
  236. if(t == nil){
  237. /* none found, make one up */
  238. if(strcmp(attr, "ip") != 0)
  239. return nil;
  240. strncpy(ipstr, val, sizeof(ipstr)-1);
  241. ip[sizeof(ip)-1] = 0;
  242. t = malloc(sizeof(*t));
  243. strcpy(t->attr, "ip");
  244. strcpy(t->val, ipstr);
  245. t->line = t;
  246. t->entry = nil;
  247. t = mine(db, t, list, 128, &needed);
  248. ndbfree(t);
  249. } else {
  250. /* found one */
  251. while(t != nil){
  252. t = reorder(t, s.t);
  253. t = mine(db, t, list, 128, &needed);
  254. ndbfree(t);
  255. t = ndbsnext(&s, attr, val);
  256. }
  257. }
  258. parseip(ip, ipstr);
  259. ipmove(net, ip);
  260. /*
  261. * now go through subnets to fill in any missing attributes
  262. */
  263. if(isv4(ip)){
  264. prefix = 127;
  265. smallestprefix = 100;
  266. } else {
  267. /* in v6, the last 8 bytes have no structure */
  268. prefix = 64;
  269. smallestprefix = 2;
  270. memset(net+8, 0, 8);
  271. }
  272. /*
  273. * to find a containing network, keep turning off
  274. * the lower bit and look for a network with
  275. * that address and a shorter mask. tedius but
  276. * complete, we may need to find a trick to speed this up.
  277. */
  278. for(; prefix >= smallestprefix; prefix--){
  279. if(needed == 0)
  280. break;
  281. if((net[prefix/8] & (1<<(7-(prefix%8)))) == 0)
  282. continue;
  283. net[prefix/8] &= ~(1<<(7-(prefix%8)));
  284. subnet(db, net, list, prefix, &needed);
  285. }
  286. /*
  287. * chain together the results and free the list
  288. */
  289. lt = &t;
  290. while(list != nil){
  291. a = list;
  292. list = a->next;
  293. *lt = a->first;
  294. if(*lt == nil && strcmp(a->attr, "ipmask") == 0){
  295. /* add a default ipmask if we need one */
  296. *lt = mallocz(sizeof( Ndbtuple), 1);
  297. strcpy((*lt)->attr, "ipmask");
  298. snprint((*lt)->val, sizeof((*lt)->val), "%M", defmask(ip));
  299. }
  300. while(nt = *lt){
  301. nt->line = nt->entry;
  302. lt = &nt->entry;
  303. }
  304. free(a);
  305. }
  306. return t;
  307. }