confutil.c
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:41k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /* Copyright (c) 1995,1996,1997 NEC Corporation.  All rights reserved.       */
  2. /*                                                                           */
  3. /* The redistribution, use and modification in source or binary forms of     */
  4. /* this software is subject to the conditions set forth in the copyright     */
  5. /* document ("Copyright") included with this distribution.                   */
  6. /*
  7.  * $Id: confutil.c,v 1.74.4.9 1998/11/13 21:36:36 wlu Exp $
  8.  */
  9. #include "socks5p.h"
  10. #include "threads.h"
  11. #include "buffer.h"
  12. #include "addr.h"
  13. #include "confutil.h"
  14. #include "log.h"
  15. #ifdef HAVE_IFADDRS_H
  16. #include <ifaddrs.h>
  17. #define ifassi(x) (((ssi *)(x))->sin_addr.s_addr)
  18. #endif
  19. #ifdef OSIOCGIFCONF
  20. #define RSIOCGIFCONF OSIOCGIFCONF
  21. #else
  22. #define RSIOCGIFCONF SIOCGIFCONF
  23. #endif
  24. #ifdef SIOCGIFADDR
  25. #define RSIOCGIFADDR SIOCGIFADDR
  26. #else
  27. #define RSIOCGIFADDR OSIOCGIFADDR
  28. #endif
  29. #ifdef SIOCGIFNETMASK
  30. #define RSIOCGIFNETMASK SIOCGIFNETMASK
  31. #else
  32. #define RSIOCGIFNETMASK OSIOCGIFNETMASK
  33. #endif
  34. IFTHREADED(extern MUTEX_T gh_mutex;)
  35. IFTHREADED(extern MUTEX_T gs_mutex;)
  36. int lsLineNo = 0;
  37. /* A function that checks if s1 is the first string in s1, and is followed   */
  38. /* by whitespace.  Used for configuration file entries.                      */
  39. static int CheckString(char *s1, char *s2) {
  40.     if (s2 == NULL) return 1;
  41.     if (strncmp(s1, s2, strlen(s2))) return 0;
  42.     if (!isspace(s1[strlen(s2)]))    return 0;
  43.     return 1;
  44. }
  45. /* A function that checks if c's string or abbreviation member is the first  */
  46. /* string in s1, and is followed by whitespace...                            */
  47. /*                                                                           */
  48. /* Arguments: s1 -- the string which we are examining                        */
  49. /* Arguments: c  -- a structure containing the string and abbreviation we    */
  50. /*                  are checking for.                                        */
  51. static int CheckStringOrAbbrev(char *s1, struct confid *c) {
  52.     char *tmp;
  53.     for (tmp = s1; *tmp && !isspace(*tmp); tmp++) if (isupper(*tmp)) *tmp = tolower(*tmp);
  54.     if (CheckString(s1, c->string)) return 1;
  55.     return CheckString(s1, c->abbrev);
  56. }
  57. /* This a malloc/realloc'ish function which takes orig, mallocs it if its    */
  58. /* Null, or reallocs it if it is non-null...pretty simple...oh, if the size  */
  59. /* is 0, and the pointer was allocated, it frees the memory, otherwise rets. */
  60. static void *remalloc(void *orig, size_t size) {
  61.     if (size == 0) {
  62. if (orig) free(orig);
  63. return NULL;
  64.     }
  65.     
  66.     if (orig == NULL) return (void *)malloc(size);
  67.     else              return (void *)realloc(orig, size);
  68. }
  69. int lsLinkedListInsertUnaligned(list **l, size_t s) {
  70.     list *templ = remalloc(NULL, s+sizeof(list));
  71.     if (templ == NULL) return -1;
  72.     templ->dataptr     = (void *)(templ+1);
  73.     templ->ptrmalloced = 0;
  74.     templ->next        = *l;
  75.     *l = templ;
  76.     return 0;
  77. }
  78. int lsLinkedListInsertAligned(list **l, size_t s) {
  79.     list *templ = remalloc(NULL, sizeof(list));
  80.     void *vptr  = remalloc(NULL, s);
  81.     if (templ == NULL || vptr == NULL) return -1;
  82.     templ->dataptr     = vptr;
  83.     templ->ptrmalloced = 1;
  84.     templ->next        = *l;
  85.     *l = templ;
  86.     return 0;
  87. }
  88. /* Delete a linked list...nothing to it really, except not freeing some ptrs */
  89. /*                                                                           */
  90. /* Arguments: l -- a ptr to the list we need to free...will be set to null.  */
  91. void lsDeleteLinkedList(list **l) {
  92.     list *tmp, *cur;
  93.     
  94.     for (tmp = *l, *l = NULL; tmp;) {
  95. cur = tmp; tmp = tmp->next;
  96. if (cur->ptrmalloced) free(cur->dataptr);
  97. free(cur);
  98.     }
  99. }
  100. /* Look at the buffer that ptr points to, and read an address...             */
  101. /*                                                                           */
  102. /* Arguments: ptr  -- a ptr to the buffer we are working with...(in/out)     */
  103. /*             na  -- a ptr to the address we are looking up...(out)         */
  104. int lsGetHostAddress(char **ptr, S5NetAddr *na) {
  105.     char *tmp, tc;
  106.     int rval;
  107.     SKIPSPACE(*ptr);
  108.     tmp = *ptr;
  109.     SKIPNSPNCOMMA(tmp);
  110.     tc = *tmp; *tmp = '';
  111.     rval = lsName2Addr(*ptr, na);
  112.     *(*ptr = tmp) = tc;
  113.     return rval;
  114. }
  115. /* Look at the buffer that ptr points to, and read a port... check ,'s       */
  116. /*                                                                           */
  117. /* Arguments: ptr  -- a ptr to the buffer we are working with...(in/out)     */
  118. /*            val  -- a ptr to the address we are looking up...(out)         */
  119. static int lsGetPort(char **ptr, u_short *val) {
  120.     char *tmp, tc;
  121.     int retval = 0;
  122.     SKIPSPACE(*ptr);
  123.     tmp = *ptr;
  124.     SKIPNSPNCOMMA(tmp);
  125.     tc = *tmp; *tmp = '';
  126.     if (tmp != *ptr) retval = lsName2Port(*ptr, NULL /* XXX OK? */, val);
  127.     else             *val = INVALIDPORT;
  128.     *(*ptr = tmp) = tc;
  129.     return retval;
  130. }
  131. /* Look at the buffer that ptr points to, and read a port... no commas       */
  132. /* Stuff the answer into an S5NetAddr...                                     */
  133. /*                                                                           */
  134. /* Arguments: ptr -- a ptr to the buffer we are working with...(in/out)      */
  135. /*             na -- a ptr to the address we are looking up...(out)          */
  136. int lsGetHostPort(char **ptr, S5NetAddr *na) {
  137.     u_short port = INVALIDPORT;
  138.     int rval;
  139.     rval = lsGetPort(ptr, &port);
  140.     lsAddrSetPort(na, port);
  141.     return rval;
  142. }
  143. /* Look at the buffer that ptr points to, and read an address and a port...  */
  144. /* The address and port are separated by ':' ...                             */
  145. /*                                                                           */
  146. /* Arguments: ptr -- a ptr to the buffer we are working with...(in/out)      */
  147. /*             na -- a ptr to the address we are looking up...(out)          */
  148. int lsGetHostAddressAndPort(char **ptr, S5NetAddr *na) {
  149.     int rval;
  150.     char *tmp, tc;
  151.     SKIPSPACE(*ptr);
  152.     tmp = *ptr;
  153.     SKIPNSPNCOLNCOM(tmp);
  154.     if (tmp == *ptr) return 0;
  155.     tc = *tmp; *tmp = '';
  156.     rval = lsName2Addr(*ptr, na);
  157.     *(*ptr = tmp) = tc;
  158.     if (rval < 0) return rval;
  159.     if (tc == ':') {
  160. (*ptr)++;
  161. return lsGetHostPort(ptr, na);
  162.     }
  163.     return 0;
  164. }
  165. /* Given ip (address in net order) return the standard subnet mask for it.   */ 
  166. static void StandardSubnetMaskForClass(struct in_addr ip, struct in_addr *mask) {
  167.     if      ((ip.s_addr & htonl(0x80000000)) == 0) mask->s_addr = htonl(0xffff0000); /* class A  */
  168.     else if ((ip.s_addr & htonl(0x40000000)) == 0) mask->s_addr = htonl(0xffffff00); /* class B  */
  169.     else if ((ip.s_addr & htonl(0x20000000)) == 0) mask->s_addr = htonl(0xfffffff0); /* class C  */
  170.     else mask->s_addr = htonl(0xffffffff);                                           /* class D  */
  171. }
  172. /* Given ip (address in net order) return the standard net mask for it.      */ 
  173. static void StandardNetMaskForClass(struct in_addr ip, struct in_addr *mask) {
  174.     if      ((ip.s_addr & htonl(0x80000000)) == 0) mask->s_addr = htonl(0xff000000); /* class A  */
  175.     else if ((ip.s_addr & htonl(0x40000000)) == 0) mask->s_addr = htonl(0xffff0000); /* class B  */
  176.     else if ((ip.s_addr & htonl(0x20000000)) == 0) mask->s_addr = htonl(0xffffff00); /* class C  */
  177.     else mask->s_addr = htonl(0xffffffff);                                           /* class D  */
  178. }
  179. /* Look at the buffer that ptr points to, and read either a net address of a */
  180. /* host and a netmask (n.n.n.n/m.m.m.m) or a abbreviated portion of that     */
  181. /* (n.n.n. n.n. or n.) or the name of a valid machine (idaho.syl.dl.nec.com) */
  182. /* or a portion of that name which must match (.syl.dl.nec.com)...           */
  183. /*                                                                           */
  184. /* Arguments: ptr  -- a ptr to the buffer we are working with...(in/out)     */
  185. /*            host -- a ptr to the address/mask we are looking up...(out)    */
  186. int lsGetHostAndMask(char **ptr, struct host *h) {
  187.     int i, nd = 0, rval = 0;
  188.     struct hostent *hp;
  189.     char *tmp, *st, c;
  190.     if (!h) return -1;
  191.     memset((char *)h, 0, sizeof(struct host));
  192.     SKIPSPACE(*ptr);
  193.     tmp = *ptr;
  194.     if (*tmp == 'n') {
  195. h->type        = IN_ADDR;
  196. h->mask.s_addr = 0xffffffff;
  197. h->ip.s_addr   = INVALIDADDR;
  198. return -1;
  199.     }
  200.     for (st = tmp; !isspace(*tmp) && *tmp != '' && *tmp != '/'; tmp++) if (*tmp == '.') nd++;
  201.     c  = *tmp; *tmp = '';
  202.     if (*st == '-') {
  203. /* - */
  204. /* This is obviously the easiest case...its a -, so any body matches */
  205. h->type        = IN_ADDR;
  206. h->mask.s_addr = htonl(0x00000000);
  207. h->ip.s_addr   = htonl(0x00000000);
  208.     } else if (c == '/') {
  209. /* n.n.n.n/[m.m.m.m|h|s|n|a] */
  210. char *end, c2;
  211. for (end = tmp+1; !isspace(*end) && *end != ''; end++);
  212. c2 = *end; *end = '';
  213. /* There was a /, so there has to have been an IP address before it. */
  214. /* Read the address, then read the mask... Pretty straight forward.  */
  215. if ((h->ip.s_addr = inet_addr(st)) == INVALIDADDR) {
  216.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "Conf: Invalid address in address/mask host pair");
  217.     rval = -1;
  218. switch (*(tmp + 1)) {
  219.     case 'h': h->mask.s_addr = htonl(0xffffffff); break;
  220.     case 's': StandardSubnetMaskForClass(h->ip, &h->mask); break;
  221.     case 'n': StandardNetMaskForClass   (h->ip, &h->mask); break;
  222.     case 'a': h->mask.s_addr = htonl(0x00000000); break;
  223.     default:  h->mask.s_addr = inet_addr(tmp+1); break;
  224. }
  225. h->type       = IN_ADDR;
  226. h->ip.s_addr &= h->mask.s_addr;
  227. if (h->mask.s_addr == htonl(0xffffffff) && getenv("SOCKS5_REVERSEMAP") != NULL) {
  228.     /* Map the IP, since the name we will be comparing it to         */
  229.     /* will already have been resolved and mapped (hopefully).       */
  230.     MUTEX_LOCK(gh_mutex);
  231.     if ((hp = gethostbyaddr((char *)&h->ip, sizeof(struct in_addr), AF_INET)) != NULL) {
  232. /* Store all the aliases and the ip addresses                */
  233. h->resolve = 1;
  234.         strncpy(h->name, hp->h_name, MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1));
  235.         h->name[MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1)] = '';
  236. for (i = 0; hp->h_aliases[i] && i < S5_HOSTALIASES_NUM; i++) {
  237.             strncpy(h->aliases[i], hp->h_aliases[i], MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1));
  238.             h->aliases[i][MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1)] = '';
  239. }
  240. h->aliascnt = i;
  241. for (i = 0; hp->h_addr_list[i] && i < S5_HOSTIP_NUM; i++) {
  242.             memcpy((char *)&h->back[i], hp->h_addr_list[i], sizeof(struct in_addr));
  243. }
  244. h->ipcnt = i;
  245.     }
  246.     MUTEX_UNLOCK(gh_mutex);
  247. }
  248. *tmp = c;
  249. tmp  = end;
  250. c    = c2;
  251.     } else if (*(tmp-1) == '.') {
  252. /* n.n.n. or n.n. or n. */
  253. /* Put a 0 on the end just for inet_addr's sake, even though it      */
  254. /* seems to work without it...its not documented so it probably      */
  255. /* won't work on some OS...restore it at the end...                  */
  256. char c2 = tmp[1];
  257. tmp[0] = '0';
  258. tmp[1] = '';
  259. if ((h->ip.s_addr = inet_addr(st)) == INVALIDADDR) {
  260.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "Conf: Invalid address in truncated address");
  261.     rval = -1;
  262. }
  263. h->type        = IN_ADDR;
  264. h->mask.s_addr = htonl(((u_int)0xffffffff) << (8*(4-nd)));
  265. h->ip.s_addr  &= h->mask.s_addr;
  266. tmp[1] = c2;
  267. tmp[0] = '';
  268.     } else if ((h->ip.s_addr = inet_addr(st)) != INVALIDADDR) {
  269. /* n.n.n.n or n.n.n or n.n or n */
  270. /* This one's really simple, inet_addr worked, and the mask          */
  271. /* should be exact, so just do it...                                 */
  272. h->type        = IN_ADDR;
  273. h->mask.s_addr = htonl(0xffffffff);
  274. h->ip.s_addr  &= h->mask.s_addr;
  275. /* Map the IP, since the name we will be comparing it to             */
  276. /* will already have been resolved and mapped (hopefully).           */
  277. if (getenv("SOCKS5_REVERSEMAP") != NULL) {
  278.     MUTEX_LOCK(gh_mutex);
  279.     if ((hp = gethostbyaddr((char *)&h->ip, sizeof(struct in_addr), AF_INET)) != NULL) {
  280. /* Store all the aliases and the ip addresses                */
  281. h->resolve = 1;
  282. strncpy(h->name, hp->h_name, MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1));
  283. h->name[MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1)] = '';
  284. for (i = 0; hp->h_aliases[i] && i < S5_HOSTALIASES_NUM; i++) {
  285.     strncpy(h->aliases[i], hp->h_aliases[i], MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1));
  286.     h->aliases[i][MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1)] = '';
  287. }
  288. h->aliascnt = i;
  289. for (i = 0; hp->h_addr_list[i] && i < S5_HOSTIP_NUM; i++) {
  290.     memcpy((char *)&h->back[i], hp->h_addr_list[i], sizeof(struct in_addr));
  291. }
  292. h->ipcnt = i;
  293.     }
  294.     MUTEX_UNLOCK(gh_mutex);
  295. }
  296.     } else {
  297. /* name */
  298. h->type    = NAME;
  299. h->resolve = (*st == '.')?0:1;
  300. /* Make this string lower case so we don't have to call (non-POSIX)  */
  301. /* strncasecmp, but instead strncmp.                                 */
  302. for (tmp = st; *tmp != ''; tmp++) if (isupper(*tmp)) *tmp = tolower(*tmp);
  303. strncpy(h->name, st, MIN(strlen(st), S5_HOSTNAME_SIZE-1));
  304. h->name[MIN(strlen(st), S5_HOSTNAME_SIZE-1)] = '';
  305. if (h->resolve) {
  306.     /* Reverse map the name, since the name we will be comparing it to   */
  307.     /* will already have been reverse and mapped (hopefully).            */
  308.     MUTEX_LOCK(gh_mutex);
  309.     if ((hp = REAL(gethostbyname)(st)) != NULL) {
  310. /* Store all the aliases and the ip addresses                */
  311.         strncpy(h->name, hp->h_name, MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1));
  312.         h->name[MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1)] = '';
  313. for (i = 0; hp->h_aliases[i] && i < S5_HOSTALIASES_NUM; i++) {
  314.             strncpy(h->aliases[i], hp->h_aliases[i], MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1));
  315.             h->aliases[i][MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1)] = '';
  316. }
  317. h->aliascnt = i;
  318. for (i = 0; hp->h_addr_list[i] && i < S5_HOSTIP_NUM; i++) {
  319.             memcpy((char *)&h->back[i], hp->h_addr_list[i], sizeof(struct in_addr));
  320. }
  321. h->ipcnt = i;
  322.     }
  323.     MUTEX_UNLOCK(gh_mutex);
  324. }
  325. h->length = strlen(h->name);
  326.     } 
  327.     *tmp = c;
  328.     SKIPNONSPACE(*ptr);
  329.     return rval;
  330. }
  331. /* Look at the buffer that ptr points to, and read either a port number or   */
  332. /* the name of a service...the name may be used in service name proxying.    */
  333. /*                                                                           */
  334. /* Arguments: ptr -- a ptr to the buffer we are working with...(in/out)      */
  335. /*            p -- a ptr to the port/service we are looking up...(out)       */
  336. int lsGetPortOrService(char **ptr, struct port *p) {
  337.     char *tmp, c, *end, ec;
  338.     int retval = 0;
  339.     u_short tmpport;
  340.     SKIPSPACE(*ptr);
  341.     tmp = *ptr;
  342.     
  343.     p->lport = htons(INVALIDPORT);
  344.     p->hport = htons(INVALIDPORT);
  345.     if (*tmp == 'n') {
  346. p->lport = htons(0);
  347. return 0;
  348.     }
  349.     if ((c = *tmp) == '-') {
  350. /* anything goes */
  351. p->lport = htons(0);
  352.     } else if (*tmp != '[' && *tmp != '(') {
  353. retval = lsGetPort(&tmp, &p->lport);
  354. p->hport = p->lport;
  355.     } else {
  356. for (end = tmp; !isspace(*end) && *end != ',' && *end != ''; end++);
  357. ec = *end; *end = '';
  358. tmp++;
  359. retval = lsName2Port(tmp, NULL /* XXX OK? */, &p->lport);
  360. *(tmp = end) = ec;
  361. if (retval) goto done;
  362. if (c == '(') {
  363.     tmpport = ntohs(p->lport) + 1;
  364.     p->lport = htons(tmpport);
  365. }
  366. if (*tmp != ',') {
  367.     p->lport = INVALIDPORT;
  368.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "Conf: Expected a ',' between ports in a range");
  369.     retval = -1;
  370.     goto done;
  371. for (end = tmp; !isspace(*end) && *end != ')' && *end != ']' && *end != ''; end++);
  372. ec = *end; *end = '';
  373. tmp++;
  374. retval = lsName2Port(tmp, NULL /* XXX OK? */, &p->hport);
  375. *end = ec;
  376. if (retval) goto done;
  377. if (ec == ')') {
  378.     tmpport = ntohs(p->hport) - 1;
  379.     p->hport = htons(tmpport);
  380. }
  381.     }
  382.   done:
  383.     SKIPNONSPACE(*ptr);
  384.     return retval;
  385. }
  386. /* Look at the buffer that ptr points to, and read the string representing   */
  387. /* valid authentication methods.                                             */
  388. /*                                                                           */
  389. /* Arguments: ptr -- a ptr to the buffer we are working with...(in/out)      */
  390. /*            val -- a ptr to the char which will hold valid auths...(out)   */
  391. int lsGetAuthMethods(char **ptr, list **val) {
  392.     char *tmp, c, tmpn[S5_NAME_SIZE];
  393.     int len, rval = 0;
  394.     SKIPSPACE(*ptr);
  395.     for (*val = NULL; **ptr != ''; (*ptr)++) {
  396. for (tmp = *ptr; *tmp != '' && *tmp != ',' && !isspace(*tmp); tmp++);
  397. c = *tmp; *tmp = '';
  398. if (tmp == *ptr) {
  399.     *tmp = c;
  400.     break;
  401. }
  402. if (!strcmp(*ptr, "-")) {
  403.     if (*val) lsDeleteLinkedList(val);
  404.     *tmp = c;
  405.     break;
  406. }
  407. if (lsLinkedListInsertUnaligned(val, 0) < 0) {
  408.     *tmp = c;
  409.     break;
  410. }
  411. len = MIN(strlen(*ptr), S5_NAME_SIZE-1);
  412. strncpy(tmpn, *ptr, len);
  413. tmpn[len] = '';
  414. *(*ptr = tmp) = c;
  415. /* Somehow, they know the auth number, so let them use it...      */
  416. if (isdigit(*tmpn)) {
  417.     if (((*val)->dataint = atoi(tmpn)) >= 0xff) {
  418.      (*val)->dataint = 0xff;
  419. rval = -1;
  420.      break;
  421.     } else if (isspace(c) || c == '') break;
  422.     continue;
  423. }
  424. /* See if the long (word) or short (letter) names match...           */
  425. if (!strcmp(tmpn, "null")           || !strcmp(tmpn, "n")) {
  426.     (*val)->dataint = AUTH_NONE;           /* null                   */
  427.     if (isspace(c) || c == '') break;
  428.     continue;
  429. } else if (!strcmp(tmpn, "krb5gss") || !strcmp(tmpn, "k")) {
  430.     (*val)->dataint = AUTH_GSSAPI;         /* kerberos               */
  431.     if (isspace(c) || c == '') break;
  432.     continue;
  433. } else if (!strcmp(tmpn, "upwd")    || !strcmp(tmpn, "u")) {
  434.     (*val)->dataint = AUTH_PASSWD;         /* passwd                 */
  435.     if (isspace(c) || c == '') break;
  436.     continue;
  437. }
  438. /* Nothing matched, so mark this as a bad entry and return -1...     */
  439. (*val)->dataint = 0xff;
  440. lsDeleteLinkedList(&(*val)->next);
  441. rval = -1;
  442. break;
  443.     }
  444.     
  445.     SKIPNONSPACE(*ptr);
  446.     return rval;
  447. }
  448. /* Look at the buffer that ptr points to, and read the string representing   */
  449. /* valid protocols...                                                        */
  450. /*                                                                           */
  451. /* Arguments: ptr -- a ptr to the buffer we are working with...(in/out)      */
  452. /*            val -- a ptr to the char which will hold valid protos...(out)  */
  453. int lsGetPermCommand(char **ptr, list **val) {
  454.     char tmpn[S5_NAME_SIZE], *tmp, c;
  455.     int len, rval = 0;
  456.     SKIPSPACE(*ptr);
  457.     for (*val = NULL; **ptr != ''; (*ptr)++) {
  458. for (tmp = *ptr; *tmp != '' && *tmp != ',' && !isspace(*tmp); tmp++);
  459. c = *tmp; *tmp = '';
  460. if (tmp == *ptr) {
  461.     *tmp = c;
  462.     break;
  463. }
  464. if (!strcmp(*ptr, "-")) {
  465.     if (*val) lsDeleteLinkedList(val);
  466.     *tmp = c;
  467.     break;
  468. }
  469. if (lsLinkedListInsertUnaligned(val, 0) < 0) {
  470.     *tmp = c;
  471.     break;
  472. }
  473. len = MIN(strlen(*ptr), S5_NAME_SIZE-1);
  474. strncpy(tmpn, *ptr, len);
  475. tmpn[len] = '';
  476. *(*ptr = tmp) = c;
  477. /* Somehow, they know the command number, so let them use it...      */
  478. if (isdigit(*tmpn)) {
  479.     if (((*val)->dataint = atoi(tmpn)) >= 0xff) {
  480.      (*val)->dataint = 0xff;
  481. rval = -1;
  482.      break;
  483.     } else if (isspace(c) || c == '') break;
  484.     continue;
  485. }
  486. /* See if the long (word) or short (letter) names match...           */
  487. if (!strcmp(tmpn, "bind")              || !strcmp(tmpn, "b")) {
  488.     (*val)->dataint = SOCKS_BIND;
  489.     if (isspace(c) || c == '') break;
  490.     continue;
  491. } else if (!strcmp(tmpn, "connect")    || !strcmp(tmpn, "c")) {
  492.     (*val)->dataint = SOCKS_CONNECT;
  493.     if (isspace(c) || c == '') break;
  494.     continue;
  495. } else if (!strcmp(tmpn, "udp")        || !strcmp(tmpn, "u")) {
  496.     (*val)->dataint = SOCKS_UDP;
  497.     if (isspace(c) || c == '') break;
  498.     continue;
  499. } else if (!strcmp(tmpn, "ping")       || !strcmp(tmpn, "p")) {
  500.     (*val)->dataint = SOCKS_PING;
  501.     if (isspace(c) || c == '') break;
  502.     continue;
  503. } else if (!strcmp(tmpn, "traceroute") || !strcmp(tmpn, "t")) {
  504.     (*val)->dataint = SOCKS_TRACER;
  505.     if (isspace(c) || c == '') break;
  506.     continue;
  507. }
  508. /* Nothing matched, so mark this as a bad entry and return -1...     */
  509. (*val)->dataint = 0xff;
  510. lsDeleteLinkedList(&(*val)->next);
  511. rval = -1;
  512. break;
  513.     }
  514.     
  515.     SKIPNONSPACE(*ptr);
  516.     return rval;
  517. }
  518. /* Look at the buffer that ptr points to, and read the string representing   */
  519. /* a list of users.  The list is comma separated with no whitespce between   */
  520. /* usernames.   "-" is a special string meaning any user is ok...            */
  521. /*                                                                           */
  522. /* Arguments: ptr  -- a ptr to the buffer we are working with...(in/out)     */
  523. /*            l    -- a ptr to the list of users which are ok...(out)        */
  524. int lsGetPermUsers(char **ptr, list **l) {
  525.     char *tmp, c;
  526.     SKIPSPACE(*ptr);
  527.     for (*l = NULL; **ptr != ''; (*ptr)++) {
  528. for (tmp = *ptr; *tmp != '' && *tmp != ',' && !isspace(*tmp); tmp++);
  529. c = *tmp; *tmp = '';
  530. if (tmp == *ptr) {
  531.     *tmp = c;
  532.     break;
  533. }
  534. if (!strcmp(*ptr, "-")) {
  535.     if (*l) lsDeleteLinkedList(l);
  536.     *tmp = c;
  537.     break;
  538. }
  539. if (lsLinkedListInsertUnaligned(l, strlen(*ptr)+1) < 0) {
  540.     *tmp = c;
  541.     break;
  542. }
  543. strcpy((*l)->dataptr, *ptr);
  544. *(*ptr = tmp) = c;
  545. if (isspace(c) || c == '') break;
  546.     }
  547.     SKIPNONSPACE(*ptr);
  548.     return 0;
  549. }
  550. /* Check to see if username appears in userlist or if userlist is NULL.      */
  551. /* If username is NULL, and the list is not, it obviously does not.          */
  552. /* Returns 1 on success 0 on failure.                                        */
  553. int lsCheckUser(list *userlist, const char *username) {
  554.     list *tmp;
  555.     if (!userlist) {
  556. /* Authentication is ok for anybody.                                 */
  557. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "Check: Checking username, %s is in -", username?username:"(null)");
  558. return 1; 
  559.     }
  560.     
  561.     if (!username) {
  562. /* Authentication is ok for nobody..                                 */
  563. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "Check: Checking username, username is (null)");
  564. return 0;
  565.     }
  566.     for (tmp = userlist; tmp != NULL; tmp = tmp->next) {
  567. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "Check: Checking if %s is %s", username, tmp->dataptr);
  568. if (!strcmp(tmp->dataptr, username)) return 1;
  569.     }
  570.       
  571.     return 0;
  572. }
  573. /* Check to see if s or name match the host pattern specified in h.  If so   */
  574. /* return 1, if not return 0.                                                */
  575. int lsCheckHost(struct host *h, const S5NetAddr *s, const char *name) {
  576.     char tmp[S5_HOSTNAME_SIZE], nbuf[MAXHOSTNAMELEN];
  577.     int offset, i;
  578.     struct in_addr addr;
  579.     /* Make sure the input address is valid                                  */
  580.     if (!s && !name) return 0;
  581.     if (s && s->sa.sa_family == AF_INET && s->sin.sin_addr.s_addr == INVALIDADDR) return 0;
  582.     /* The address was stored, not the name => compare addresses.            */
  583.     if (h->type == IN_ADDR) {
  584.   if (h->ip.s_addr == INVALIDADDR) return 0;
  585. /* It is all....                                                     */
  586. if (h->ip.s_addr == htonl(0x00000000) && h->mask.s_addr == htonl(0x00000000)) return 1;
  587. /* s is S5NAME but IP is not mapped...                               */
  588. if ((!s || s->sa.sa_family == AF_S5NAME) && !h->resolve) return 0;
  589. /* only name is available...                                         */
  590. if (!s) {
  591.     if (!strcmp(h->name, name)) return 1;
  592.     for (i = 0; i < h->aliascnt; i++) {
  593.      if (!strcmp(h->aliases[i], name)) return 1;
  594.     }
  595.     return 0;
  596. }
  597. if (s->sa.sa_family == AF_S5NAME) {
  598.     if (!strcmp(h->name, s->sn.sn_name)) return 1;
  599.     for (i = 0; i < h->aliascnt; i++) {
  600.      if (!strcmp(h->aliases[i], s->sn.sn_name)) return 1;
  601.     }
  602.     return 0;
  603. }
  604. /* s is AF_INET...                                                   */
  605. if (s->sin.sin_addr.s_addr != INADDR_ANY) addr = s->sin.sin_addr;
  606. else addr.s_addr = (name)?inet_addr((char *)name):INVALIDADDR;
  607. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "Check: Checking host address (%08x == %08x)?", addr.s_addr & h->mask.s_addr, h->ip.s_addr);
  608. if ((addr.s_addr & h->mask.s_addr) == h->ip.s_addr) return 1;
  609. for (i = 0; i < h->ipcnt; i++) {
  610.     if (h->back[i].s_addr == addr.s_addr) return 1;
  611. }
  612. /* last possibility, the name maches...                               */
  613. if (name && h->resolve) {
  614.     if (!strcmp(h->name, name)) return 1;
  615.     for (i = 0; i < h->aliascnt; i++) {
  616.      if (!strcmp(h->aliases[i], name)) return 1;
  617.     }
  618. }
  619. return 0;
  620.     }
  621.     /* The name was stored, not the address => compare names.                */
  622.     /* If we stored a backup address, check and see if it matches...         */
  623.     if (h->resolve) {
  624.      if (s && s->sa.sa_family == AF_INET && s->sin.sin_addr.s_addr != INADDR_ANY) addr = s->sin.sin_addr;
  625. else addr.s_addr = (name)?inet_addr((char *)name):INVALIDADDR;
  626. for (i = 0; i < h->ipcnt; i++) {
  627.     if (h->back[i].s_addr == addr.s_addr) return 1;
  628. }
  629.     }
  630.     if (s && s->sa.sa_family == AF_S5NAME) strcpy(tmp, s->sn.sn_name);
  631.     else if (name) strcpy(tmp, name);
  632.     else if (s && s->sa.sa_family == AF_INET) { 
  633.      struct hostent *hp = NULL;
  634.         MUTEX_LOCK(gh_mutex);
  635.         if (!(hp = gethostbyaddr((char *)&s->sin.sin_addr.s_addr, sizeof(struct in_addr), AF_INET))) {
  636.             MUTEX_UNLOCK(gh_mutex);
  637.             return 0;
  638.         }
  639.      strcpy(tmp, hp->h_name);
  640.         MUTEX_UNLOCK(gh_mutex);
  641.     } else return 0;
  642.     for (i = 0; tmp[i] != ''; i++) nbuf[i] = (isupper(tmp[i]))?tolower(tmp[i]):tmp[i];
  643.     nbuf[i] = '';
  644.     
  645.     if (h->resolve) {
  646. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "Check: Checking host name  (%s is %s)?",nbuf, h->name);
  647. if (!strcmp(h->name, nbuf)) return 1;
  648. for (i = 0; i < h->aliascnt; i++) {
  649.     if (!strcmp(h->aliases[i], nbuf)) return 1;
  650. }
  651. return 0;
  652.     } else {
  653.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "Check: Checking host domain (%s is in %s)?", nbuf, h->name);
  654.      /* How much longer is name than the stored one?  If its too short, well  */
  655.      /* its not a match...If it has to be exact and its too long, ditto.  If  */
  656.      /* h->name isn't the last part of name, ditto...otherwise, a match.   */
  657.      if ((offset = i - h->length) < 0) return 0;
  658.      if (strncmp(nbuf+offset, h->name, h->length)) return 0;
  659.      return 1;
  660.     }
  661. }
  662. /* Check to see if s or name match the port specified by p.                  */
  663. int lsCheckPort(struct port *p, const S5NetAddr *s, const char *name, char *proto) {
  664.     u_short port = s?s->sin.sin_port:0;
  665.     struct servent *sp;
  666.     MUTEX_LOCK(gs_mutex);
  667.     if (port == 0 && name && (sp = getservbyname((char *)name, proto))) port = sp->s_port;
  668.     MUTEX_UNLOCK(gs_mutex);
  669.     /* compare the port number to the range of numbers we stored....     */
  670.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "Check: Checking port range   (%d <= %d <= %d)?", ntohs(p->lport), ntohs(port), ntohs(p->hport));
  671.     return ((ntohs(port) < ntohs(p->lport)) || (ntohs(port) > ntohs(p->hport)))?0:1;
  672. }
  673. /* Check to see if byte appears in bytes, a list of bytes.                   */
  674. /*                                                                           */
  675. /* Arguments: bytes - the list of bytes we're checking                       */
  676. /*            byte  - the byte we're looking for in bytes                    */
  677. /*            name  - a name for the logs describing what this check is      */
  678. int lsCheckByte(list *bytes, u_char byte, const char *name) {
  679.     list *tl;
  680.     
  681.     if (!bytes) {
  682. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "Check: Checking %s: Anything is ok ", name);
  683. return 1;
  684.     }
  685.     for (tl = bytes; tl; tl = tl->next) {
  686. if (tl->dataint == (int)byte && tl->dataint != 0xff) {
  687.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "Check: Checking %s: %d matched ", name, (int)byte);
  688.     return 1;
  689. } else {
  690.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "Check: Checking %s: %d didn't match %d", name, tl->dataint, (int)byte);
  691. }
  692.     }
  693.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, "Check: Checking %s: No match for %d", name, (int)byte);
  694.     return 0;
  695. }
  696. /* A function for use in LoopThroughFile which increments the number of      */
  697. /* entries of this line type that need to be allocated...                    */
  698. static void ClassifyLine(confid *confids, int nids, int indx, char *tmp) {
  699.     if (indx >= 0 && indx < nids) {
  700. if (confids[indx].number) (*confids[indx].number)++;
  701. return;
  702.     }
  703.     SKIPSPACE(tmp);
  704.     if (*tmp == 'n' || *tmp =='') return;
  705.     
  706.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Bad line in configuration file: %d", lsLineNo);
  707. }
  708. /* A function for use in LoopThroughFile which actually reads the line into  */
  709. /* the appropriate structure, by calling the right line handler...           */
  710. static void ProcessLine(confid *confids, int nids, int indx, char *tmp) {
  711.     char *end, c;
  712.     for (end = tmp; *end != 'n' && *end != ''; end++);
  713.     c = *end; *end = '';
  714.     
  715.     if (indx < nids)
  716. confids[indx].handler(confids[indx].array, confids[indx].cnum?(*confids[indx].cnum)++:0, indx, tmp);
  717.     *end = c;
  718. }
  719. /* LoopTroughFile() reads through (line by line) the file (read into buf)    */
  720. /* and performs func on each line of the file...telling func what kind of    */
  721. /* line it seems to be...                                                    */
  722. static void LoopThroughFile(char *buf, int fsize, confid *confids, int nids, void (*func)(confid *, int, int, char *)) {
  723.     char *tmp, *nl;
  724.     int i;
  725.     
  726.     for (lsLineNo = 1, tmp = buf; tmp && tmp < buf+fsize; tmp = nl+1, lsLineNo++) {
  727. if ((nl = strchr(tmp, 'n')) != NULL) *nl = '';
  728.         SKIPSPACE(tmp);
  729. if (*tmp != '#' && *tmp != '') {
  730.     /* Do this even if "i" is too big (so we only warn once)         */
  731.     for (i = 0; i < nids; i++) if (CheckStringOrAbbrev(tmp, &confids[i])) break;
  732.     func(confids, nids, i, tmp); 
  733. }
  734. if (!nl) break; else *nl = 'n';
  735.     }
  736. }
  737. /* A function that reads teh configuration file SRVCONF_FILE int buf and     */
  738. /* sets *size to be the size of the new buffer...if something goes wrong, it */
  739. /* returns NULL indicating there is no valid configuration (for now)...      */
  740. static char *ReadConfigFile(const char *filename, int *sizep) {
  741.     int size = 1024 * 1024;
  742.     char *buf = NULL;
  743.     S5IOHandle fd;
  744.     struct stat sb;
  745.     *sizep = 0;
  746.     while ((fd = open(filename, O_RDONLY)) < 0 && errno == EINTR);
  747.     if (fd < 0) {
  748. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Config: Error opening config file (%s): %m", filename);
  749. return NULL;
  750.     }
  751.     if (fstat(fd, &sb) < 0) {
  752. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Config: Error stating open config file (%s): %m", filename);
  753. goto end;
  754.     }
  755.     size = sb.st_size;
  756.     
  757.     if ((buf = (char *)malloc((size+1)*sizeof(char))) == NULL) {
  758. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Config: Error allocating space for config file (%s): %m", filename);
  759. goto end;
  760.     }
  761.     
  762.     if ((size = READFILE(fd, buf, size)) < 0) {
  763. S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Config: Error reading open config file (%s): %m", filename);
  764. free(buf);
  765. buf = NULL;
  766.     } else {
  767. buf[size] = '';
  768. *sizep = size;
  769.     }
  770.   end:
  771.     REAL(close)(fd);
  772.     return buf;
  773. }
  774. /* ReadConfig() reads the configuration file specified by SRVCONF_FILE.  It  */
  775. /* first figures out how much memory it will need, allocates the memory,     */
  776. /* reads in the array, counts the number of entries of each type, and        */
  777. /* allocates (or reallocates) the appropriate arrays those entries are kept  */
  778. /* in.  After all that, it actually reads in the entries themselves (from    */
  779. /* memory) and rstarts the logging in case its variables may have changed.   */
  780. /*                                                                           */
  781. /* Globals Affected: -- too many to list... big ones are...                  */
  782. /*                   -- confids, where the entries are stored.               */
  783. /*                   -- environ, which may have new entries in it...         */
  784. void lsReadConfig(const char *filename, confid *confids, int nids) {
  785.     int i, fsize;
  786.     char *buf;
  787.     if ((buf = ReadConfigFile(filename, &fsize)) == NULL) return; /* read in */
  788.     LoopThroughFile(buf, fsize, confids, nids, ClassifyLine);     /* count   */
  789.     for (i = 0; i < nids; i++) if (confids[i].size > 0) {
  790. *confids[i].array = (void *)remalloc(*confids[i].array, *confids[i].number * confids[i].size);
  791. memset(*confids[i].array, 0, *confids[i].number * confids[i].size);
  792.     }
  793.     LoopThroughFile(buf, fsize, confids, nids, ProcessLine);      /* process */
  794.     free(buf);
  795. }
  796. /* check out interface's condition                                           */
  797. int lsLookupIntfc(S5IOHandle sd, int query, struct ifreq *ifr) {
  798.     int rval = -1;
  799.     S5IOHandle osd = (sd != S5InvalidIOHandle)?sd:socket(AF_INET, SOCK_DGRAM, 0);
  800.     if (osd == S5InvalidIOHandle) return rval;
  801.     memset((char *)&ifr->ifr_ifru, 0, sizeof(ifr->ifr_ifru));
  802.     switch (query) {
  803.     case NET_STAT:
  804.         if (ioctl(osd, SIOCGIFFLAGS, (char *)ifr) == 0) {
  805.          if (!(ifr->ifr_flags & (IFF_UP | IFF_RUNNING))) {
  806.         rval = 0;
  807.     } else rval = 1;
  808. }
  809. break;
  810.     case NET_TYPE:
  811.         if (ioctl(osd, SIOCGIFFLAGS, (char *)ifr) == 0) {
  812.             if ((ifr->ifr_flags & IFF_POINTOPOINT)) rval = 1;
  813.             else rval = 0;
  814.         }
  815.         break;
  816.     case NET_ADDR:
  817. #ifdef linux
  818.         ((struct sockaddr *)&ifr->ifr_addr)->sa_family = AF_INET;
  819. #endif
  820.      if (ioctl(osd, RSIOCGIFADDR, (char *)ifr) == 0) rval = 0;
  821. break;
  822.     case NET_MASK:
  823.      if (ioctl(osd, RSIOCGIFNETMASK, (char *)ifr) == 0) rval = 0;
  824. break;
  825.     default:
  826. break;
  827.     }
  828.     if (sd == S5InvalidIOHandle && osd != S5InvalidIOHandle) CLOSESOCKET(osd);
  829.     return rval;
  830. }
  831. /* Get a list of valid interfaces...                                         */
  832. void lsSetupIntfcs(struct intfc **intfc, int *cnt) { 
  833. #ifdef HAVE_GETIFADDRS
  834.     struct ifaddrs *ifp, *ibuf = NULL;
  835. #else
  836.     struct ifreq ibuf[1024];
  837.     struct ifconf ifc;
  838.     S5IOHandle s;
  839. #endif
  840.     struct intfc *pintfc;
  841.     struct intaddr *pintaddr;
  842.     struct in_addr tmpaddr;
  843.     char tmpname[16];
  844.     int i, j, k, m, n;
  845.     if (*intfc) {
  846. if (intfc[0]->addrlist) free(intfc[0]->addrlist);
  847.         free(*intfc);
  848.         *intfc = NULL;
  849.     }
  850.     *cnt = 0;
  851. #ifdef HAVE_GETIFADDRS
  852.     if (getifaddrs(&ibuf) < 0 || !ibuf) {
  853.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Interface Query: Error looking up interface names");
  854.         return;
  855.     }
  856.     n = 0;
  857.     strcpy(tmpname, ibuf->ifa_name);
  858. #else
  859.     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == S5InvalidIOHandle) {
  860.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Interface Query: socket: %m");
  861.         return;
  862.     }
  863.     ifc.ifc_len = sizeof(ibuf);
  864.     ifc.ifc_buf = (caddr_t)ibuf;
  865.     memset((char *)ibuf, 0, sizeof(ibuf));
  866.     /* Get the list of all the interfaces...                                */
  867.     if (ioctl(s, RSIOCGIFCONF, (char *)&ifc) < 0 || ifc.ifc_len < sizeof(struct ifreq)) {
  868. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Interface Query: Error looking up interface names");
  869. CLOSESOCKET(s);
  870. return;
  871.     }
  872.     n = ifc.ifc_len/sizeof(struct ifreq);
  873.     if (n > 0) strcpy(tmpname, ibuf[0].ifr_name);
  874. #endif
  875.     /* Walk through the list and count the interfaces that are configured   */
  876.     /* with IP...                                                           */
  877.     i = 0; j = 0; k = 0;
  878.     tmpaddr.s_addr = 0L;
  879. #ifdef HAVE_GETIFADDRS
  880.     for (ifp = ibuf; ifp; ifp = ifp->ifa_next) {
  881.         if (strcmp(tmpname, ifp->ifa_name)) {
  882.             if (n) j++;
  883.             n = 0;
  884.             strcpy(tmpname, ifp->ifa_name);
  885.         }
  886.         i = (ifp->ifa_flags & (IFF_UP | IFF_RUNNING))?1:0;
  887.         if (i && ifp->ifa_addr->sa_family != AF_INET) continue;
  888.         if (!i && !(ifp->ifa_flags & IFF_POINTOPOINT)) continue;
  889.         n = 1;
  890.         if (!i || ifassi(ifp->ifa_addr) == 0L) continue;
  891.         if (k > 0 && ifassi(ifp->ifa_addr) == tmpaddr.s_addr) continue;
  892.         tmpaddr.s_addr = ifassi(ifp->ifa_addr);
  893.         k++;
  894.     }
  895.     if (n) j++;
  896. #else
  897.     for (; i < n; i++) {
  898. if (strcmp(tmpname, ibuf[i].ifr_name)) {
  899.     j++;
  900.     strcpy(tmpname, ibuf[i].ifr_name);
  901. }
  902. if (lsLookupIntfc(s, NET_ADDR, &ibuf[i]) < 0) continue;
  903. if (ifssi(ibuf[i])->sin_family != AF_INET) continue;
  904. if (k > 0 && tmpaddr.s_addr == ifssi(ibuf[i])->sin_addr.s_addr) continue;
  905. tmpaddr.s_addr = ifssi(ibuf[i])->sin_addr.s_addr;
  906. k++;
  907.     }
  908.     j++;
  909. #endif
  910.     if ((pintfc = (struct intfc *)calloc(j, sizeof(struct intfc))) == NULL) {
  911. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Interface Query: no space");
  912. return;
  913.     }
  914.     if ((pintaddr = (struct intaddr *)calloc(k, sizeof(struct intaddr))) == NULL) {
  915. S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Interface Query: no space");
  916. free(pintfc);
  917. return;
  918.     }
  919.     /* Store IP-configured interfaces information...                        */
  920.     i = 0; j = 0; k = 0;
  921. #ifdef HAVE_GETIFADDRS
  922.     strcpy(pintfc[j].name, ibuf->ifa_name);
  923.     pintfc[j].up = (ibuf->ifa_flags & (IFF_UP | IFF_RUNNING))?1:0;
  924.     pintfc[j].type = (ibuf->ifa_flags & IFF_POINTOPOINT)?1:0;
  925.     pintfc[j].addrlist = &pintaddr[k];
  926.     pintfc[j].addrcnt = 0;
  927.     n = 0;
  928.     m = 0;
  929.     for (ifp = ibuf; ifp; ifp = ifp->ifa_next) {
  930.         if (strcmp(pintfc[j].name, ifp->ifa_name)) {
  931.             pintfc[j].addrcnt = m;
  932.             S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Interface Query: if%d is %s(%d) with %d IPs", j, pintfc[j].name, pintfc[j].up, m);
  933.             if (n) j++;
  934.             strcpy(pintfc[j].name, ifp->ifa_name);
  935.             pintfc[j].up = (ifp->ifa_flags & (IFF_UP | IFF_RUNNING))?1:0;
  936.             pintfc[j].type = (ifp->ifa_flags & IFF_POINTOPOINT)?1:0;
  937.             pintfc[j].addrlist = &pintaddr[k];
  938.             pintfc[j].addrcnt = 0;
  939.             n = 0;
  940.             m = 0;
  941.         }
  942.         if (pintfc[j].up && ifp->ifa_addr->sa_family != AF_INET) continue;
  943.         if (!pintfc[j].up && !pintfc[j].type) continue;
  944.         n = 1;
  945.         if (!pintfc[j].up || ifassi(ifp->ifa_addr) == 0L) continue;
  946.         if (k > 0 && ifassi(ifp->ifa_addr) == pintaddr[k-1].ip.s_addr) continue;
  947.         pintaddr[k].ip.s_addr = ifassi(ifp->ifa_addr);
  948.         pintaddr[k].net.s_addr = ifassi(ifp->ifa_netmask);
  949.         m++; k++;
  950.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Interface Query: if%d addr/mask is %08x:%08x", j, pintaddr[k-1].ip.s_addr, pintaddr[k-1].net.s_addr);
  951.     }
  952.     pintfc[j].addrcnt = m;
  953.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Interface Query: if%d is %s(%d) with %d IPs", j, pintfc[j].name, pintfc[j].up, m);
  954.     if (n) j++;
  955.     *cnt = j;
  956.     *intfc = pintfc;
  957.     free(ibuf);
  958. #else
  959.     strcpy(pintfc[j].name, ibuf[i].ifr_name);
  960.     pintfc[j].up = lsLookupIntfc(s, NET_STAT, &ibuf[i]);
  961.     pintfc[j].type = lsLookupIntfc(s, NET_TYPE, &ibuf[i]);
  962.     pintfc[j].addrlist = &pintaddr[k];
  963.     pintfc[j].addrcnt = 0;
  964.     m = 0;
  965.     for (; i < n; i++) {
  966. if (strcmp(pintfc[j].name, ibuf[i].ifr_name)) {
  967.     pintfc[j].addrcnt = m;
  968.          S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Interface Query: if%d is %s(%d) with %d IPs", j, pintfc[j].name, pintfc[j].up, m);
  969.     j++;
  970.     strcpy(pintfc[j].name, ibuf[i].ifr_name);
  971.     pintfc[j].up = lsLookupIntfc(s, NET_STAT, &ibuf[i]);
  972.             pintfc[j].type = lsLookupIntfc(s, NET_TYPE, &ibuf[i]);
  973.     pintfc[j].addrlist = &pintaddr[k];
  974.     pintfc[j].addrcnt = 0;
  975.     m = 0;
  976. }
  977. if (lsLookupIntfc(s, NET_ADDR, &ibuf[i]) < 0) continue;
  978. if (ifssi(ibuf[i])->sin_family != AF_INET) continue;
  979. if (k > 0 && pintaddr[k-1].ip.s_addr == ifssi(ibuf[i])->sin_addr.s_addr) continue;
  980. pintaddr[k].ip.s_addr = ifssi(ibuf[i])->sin_addr.s_addr;
  981. if (lsLookupIntfc(s, NET_MASK, &ibuf[i]) >= 0) {
  982.     pintaddr[k].net.s_addr = ifssi(ibuf[i])->sin_addr.s_addr;
  983. } else pintaddr[k].net.s_addr = 0xffffffff;
  984. m++; k++;
  985.      S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Interface Query: if%d addr/mask is %08x:%08x", j, pintaddr[k-1].ip.s_addr, pintaddr[k-1].net.s_addr);
  986.     }
  987.     pintfc[j].addrcnt = m;
  988.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Interface Query: if%d is %s(%d) with %d IPs", j, pintfc[j].name, pintfc[j].up, m);
  989.     *cnt = ++j;
  990.     *intfc = pintfc;
  991.     CLOSESOCKET(s);
  992. #endif
  993. }