ndbipinfo.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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 <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. #include <ndb.h>
  13. #include <ip.h>
  14. enum
  15. {
  16. Ffound= 1<<0,
  17. Fignore=1<<1,
  18. Faddr= 1<<2,
  19. };
  20. static Ndbtuple* filter(Ndb *db, Ndbtuple *t, Ndbtuple *f);
  21. static Ndbtuple* mkfilter(int argc, char **argv);
  22. static int filtercomplete(Ndbtuple *f);
  23. static int prefixlen(uint8_t *ip);
  24. static Ndbtuple* subnet(Ndb *db, uint8_t *net, Ndbtuple *f,
  25. int prefix);
  26. /* make a filter to be used in filter */
  27. static Ndbtuple*
  28. mkfilter(int argc, char **argv)
  29. {
  30. Ndbtuple *t, *first, *last;
  31. char *p;
  32. last = first = nil;
  33. while(argc-- > 0){
  34. t = ndbnew(0, 0);
  35. if(first)
  36. last->entry = t;
  37. else
  38. first = t;
  39. last = t;
  40. p = *argv++;
  41. if(*p == '@'){ /* @attr=val ? */
  42. t->ptr |= Faddr; /* return resolved address(es) */
  43. p++;
  44. }
  45. strncpy(t->attr, p, sizeof(t->attr)-1);
  46. }
  47. ndbsetmalloctag(first, getcallerpc(&argc));
  48. return first;
  49. }
  50. /* return true if every pair of filter has been used */
  51. static int
  52. filtercomplete(Ndbtuple *f)
  53. {
  54. for(; f; f = f->entry)
  55. if((f->ptr & Fignore) == 0)
  56. return 0;
  57. return 1;
  58. }
  59. /* set the attribute of all entries in a tuple */
  60. static Ndbtuple*
  61. setattr(Ndbtuple *t, char *attr)
  62. {
  63. Ndbtuple *nt;
  64. for(nt = t; nt; nt = nt->entry)
  65. strcpy(nt->attr, attr);
  66. return t;
  67. }
  68. /*
  69. * return only the attr/value pairs in t maching the filter, f.
  70. * others are freed. line structure is preserved.
  71. */
  72. static Ndbtuple*
  73. filter(Ndb *db, Ndbtuple *t, Ndbtuple *f)
  74. {
  75. Ndbtuple *nt, *nf, *next;
  76. /* filter out what we don't want */
  77. for(nt = t; nt; nt = next){
  78. next = nt->entry;
  79. /* look through filter */
  80. for(nf = f; nf != nil; nf = nf->entry){
  81. if(!(nf->ptr&Fignore) && strcmp(nt->attr, nf->attr) == 0)
  82. break;
  83. }
  84. if(nf == nil){
  85. /* remove nt from t */
  86. t = ndbdiscard(t, nt);
  87. } else {
  88. if(nf->ptr & Faddr)
  89. t = ndbsubstitute(t, nt, setattr(ndbgetipaddr(db, nt->val), nt->attr));
  90. nf->ptr |= Ffound;
  91. }
  92. }
  93. /* remember filter etnries that matched */
  94. for(nf = f; nf != nil; nf = nf->entry)
  95. if(nf->ptr & Ffound)
  96. nf->ptr = (nf->ptr & ~Ffound) | Fignore;
  97. ndbsetmalloctag(t, getcallerpc(&db));
  98. return t;
  99. }
  100. static int
  101. prefixlen(uint8_t *ip)
  102. {
  103. int y, i;
  104. for(y = IPaddrlen-1; y >= 0; y--)
  105. for(i = 8; i > 0; i--)
  106. if(ip[y] & (1<<(8-i)))
  107. return y*8 + i;
  108. return 0;
  109. }
  110. /*
  111. * look through a containing subset
  112. */
  113. static Ndbtuple*
  114. subnet(Ndb *db, uint8_t *net, Ndbtuple *f, int prefix)
  115. {
  116. Ndbs s;
  117. Ndbtuple *t, *nt, *xt;
  118. char netstr[128];
  119. uint8_t mask[IPaddrlen];
  120. int masklen;
  121. t = nil;
  122. sprint(netstr, "%I", net);
  123. nt = ndbsearch(db, &s, "ip", netstr);
  124. while(nt != nil){
  125. xt = ndbfindattr(nt, nt, "ipnet");
  126. if(xt){
  127. xt = ndbfindattr(nt, nt, "ipmask");
  128. if(xt)
  129. parseipmask(mask, xt->val);
  130. else
  131. ipmove(mask, defmask(net));
  132. masklen = prefixlen(mask);
  133. if(masklen <= prefix){
  134. t = ndbconcatenate(t, filter(db, nt, f));
  135. nt = nil;
  136. }
  137. }
  138. ndbfree(nt);
  139. nt = ndbsnext(&s, "ip", netstr);
  140. }
  141. ndbsetmalloctag(t, getcallerpc(&db));
  142. return t;
  143. }
  144. /*
  145. * fill in all the requested attributes for a system.
  146. * if the system's entry doesn't have all required,
  147. * walk through successively more inclusive networks
  148. * for inherited attributes.
  149. */
  150. Ndbtuple*
  151. ndbipinfo(Ndb *db, char *attr, char *val, char **alist, int n)
  152. {
  153. Ndbtuple *t, *nt, *f;
  154. Ndbs s;
  155. char *ipstr;
  156. uint8_t net[IPaddrlen], ip[IPaddrlen];
  157. int prefix, smallestprefix, force;
  158. int64_t r;
  159. /* just in case */
  160. fmtinstall('I', eipfmt);
  161. fmtinstall('M', eipfmt);
  162. /* get needed attributes */
  163. f = mkfilter(n, alist);
  164. /*
  165. * first look for a matching entry with an ip address
  166. */
  167. t = nil;
  168. ipstr = ndbgetvalue(db, &s, attr, val, "ip", &nt);
  169. if(ipstr == nil){
  170. /* none found, make one up */
  171. if(strcmp(attr, "ip") != 0) {
  172. ndbfree(f);
  173. return nil;
  174. }
  175. t = ndbnew("ip", val);
  176. t->line = t;
  177. t->entry = nil;
  178. r = parseip(net, val);
  179. if(r == -1)
  180. ndbfree(t);
  181. } else {
  182. /* found one */
  183. while(nt != nil){
  184. nt = ndbreorder(nt, s.t);
  185. t = ndbconcatenate(t, nt);
  186. nt = ndbsnext(&s, attr, val);
  187. }
  188. r = parseip(net, ipstr);
  189. free(ipstr);
  190. }
  191. if(r < 0){
  192. ndbfree(f);
  193. return nil;
  194. }
  195. ipmove(ip, net);
  196. t = filter(db, t, f);
  197. /*
  198. * now go through subnets to fill in any missing attributes
  199. */
  200. if(isv4(net)){
  201. prefix = 127;
  202. smallestprefix = 100;
  203. force = 0;
  204. } else {
  205. /* in v6, the last 8 bytes have no structure (we hope) */
  206. prefix = 64;
  207. smallestprefix = 2;
  208. memset(net+8, 0, 8);
  209. force = 1;
  210. }
  211. /*
  212. * to find a containing network, keep turning off
  213. * the lower bit and look for a network with
  214. * that address and a shorter mask. tedius but
  215. * complete, we may need to find a trick to speed this up.
  216. */
  217. for(; prefix >= smallestprefix; prefix--){
  218. if(filtercomplete(f))
  219. break;
  220. if(!force && (net[prefix/8] & (1<<(7-(prefix%8)))) == 0)
  221. continue;
  222. force = 0;
  223. net[prefix/8] &= ~(1<<(7-(prefix%8)));
  224. t = ndbconcatenate(t, subnet(db, net, f, prefix));
  225. }
  226. /*
  227. * if there's an unfulfilled ipmask, make one up
  228. */
  229. nt = ndbfindattr(f, f, "ipmask");
  230. if(nt && !(nt->ptr & Fignore)){
  231. char x[64];
  232. snprint(x, sizeof(x), "%M", defmask(ip));
  233. t = ndbconcatenate(t, ndbnew("ipmask", x));
  234. }
  235. ndbfree(f);
  236. ndbsetmalloctag(t, getcallerpc(&db));
  237. return t;
  238. }