summaryrefslogtreecommitdiff
path: root/ipme.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipme.c')
-rw-r--r--ipme.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/ipme.c b/ipme.c
new file mode 100644
index 0000000..3c86127
--- /dev/null
+++ b/ipme.c
@@ -0,0 +1,100 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#ifndef SIOCGIFCONF /* whatever works */
+#include <sys/sockio.h>
+#endif
+#include "hassalen.h"
+#include "byte.h"
+#include "ip.h"
+#include "ipalloc.h"
+#include "stralloc.h"
+#include "ipme.h"
+
+static int ipmeok = 0;
+ipalloc ipme = {0};
+
+int ipme_is(ip)
+struct ip_address *ip;
+{
+ int i;
+ if (ipme_init() != 1) return -1;
+ for (i = 0;i < ipme.len;++i)
+ if (byte_equal(&ipme.ix[i].ip,4,ip))
+ return 1;
+ return 0;
+}
+
+static stralloc buf = {0};
+
+int ipme_init()
+{
+ struct ifconf ifc;
+ char *x;
+ struct ifreq *ifr;
+ struct sockaddr_in *sin;
+ int len;
+ int s;
+ struct ip_mx ix;
+
+ if (ipmeok) return 1;
+ if (!ipalloc_readyplus(&ipme,0)) return 0;
+ ipme.len = 0;
+ ix.pref = 0;
+
+ /* 0.0.0.0 is a special address which always refers to
+ * "this host, this network", according to RFC 1122, Sec. 3.2.1.3a.
+ */
+ byte_copy(&ix.ip,4,"\0\0\0\0");
+ if (!ipalloc_append(&ipme,&ix)) { return 0; }
+ if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) return -1;
+
+ len = 256;
+ for (;;) {
+ if (!stralloc_ready(&buf,len)) { close(s); return 0; }
+ buf.len = 0;
+ ifc.ifc_buf = buf.s;
+ ifc.ifc_len = len;
+ if (ioctl(s,SIOCGIFCONF,&ifc) >= 0) /* > is for System V */
+ if (ifc.ifc_len + sizeof(*ifr) + 64 < len) { /* what a stupid interface */
+ buf.len = ifc.ifc_len;
+ break;
+ }
+ if (len > 200000) { close(s); return -1; }
+ len += 100 + (len >> 2);
+ }
+ x = buf.s;
+ while (x < buf.s + buf.len) {
+ ifr = (struct ifreq *) x;
+#ifdef HASSALEN
+ len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
+ if (len < sizeof(*ifr))
+ len = sizeof(*ifr);
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+ sin = (struct sockaddr_in *) &ifr->ifr_addr;
+ byte_copy(&ix.ip,4,&sin->sin_addr);
+ if (ioctl(s,SIOCGIFFLAGS,x) == 0)
+ if (ifr->ifr_flags & IFF_UP)
+ if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; }
+ }
+#else
+ len = sizeof(*ifr);
+ if (ioctl(s,SIOCGIFFLAGS,x) == 0)
+ if (ifr->ifr_flags & IFF_UP)
+ if (ioctl(s,SIOCGIFADDR,x) == 0)
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+ sin = (struct sockaddr_in *) &ifr->ifr_addr;
+ byte_copy(&ix.ip,4,&sin->sin_addr);
+ if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; }
+ }
+#endif
+ x += len;
+ }
+ close(s);
+ ipmeok = 1;
+ return 1;
+}