00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "config.h"
00010
00011 #include <iphlpapi.h>
00012
00013 #include <ctype.h>
00014 #include <errno.h>
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <string.h>
00018
00019 #include "dnet.h"
00020
00021 struct ifcombo {
00022 DWORD *idx;
00023 int cnt;
00024 int max;
00025 };
00026
00027 #define MIB_IF_TYPE_MAX 32
00028
00029 struct intf_handle {
00030 struct ifcombo ifcombo[MIB_IF_TYPE_MAX];
00031 MIB_IFTABLE *iftable;
00032 MIB_IPADDRTABLE *iptable;
00033 };
00034
00035 static char *
00036 _ifcombo_name(int type)
00037 {
00038 char *name = "net";
00039
00040 if (type == MIB_IF_TYPE_ETHERNET) {
00041 name = "eth";
00042 } else if (type == MIB_IF_TYPE_TOKENRING) {
00043 name = "tr";
00044 } else if (type == MIB_IF_TYPE_FDDI) {
00045 name = "fddi";
00046 } else if (type == MIB_IF_TYPE_PPP) {
00047 name = "ppp";
00048 } else if (type == MIB_IF_TYPE_LOOPBACK) {
00049 name = "lo";
00050 } else if (type == MIB_IF_TYPE_SLIP) {
00051 name = "sl";
00052 }
00053 return (name);
00054 }
00055
00056 static int
00057 _ifcombo_type(const char *device)
00058 {
00059 int type = INTF_TYPE_OTHER;
00060
00061 if (strncmp(device, "eth", 3) == 0) {
00062 type = INTF_TYPE_ETH;
00063 } else if (strncmp(device, "tr", 2) == 0) {
00064 type = INTF_TYPE_TOKENRING;
00065 } else if (strncmp(device, "fd", 2) == 0) {
00066 type = INTF_TYPE_FDDI;
00067 } else if (strncmp(device, "ppp", 3) == 0) {
00068 type = INTF_TYPE_PPP;
00069 } else if (strncmp(device, "lo", 2) == 0) {
00070 type = INTF_TYPE_LOOPBACK;
00071 } else if (strncmp(device, "sl", 2) == 0) {
00072 type = INTF_TYPE_SLIP;
00073 }
00074 return (type);
00075 }
00076
00077 static void
00078 _ifcombo_add(struct ifcombo *ifc, DWORD idx)
00079 {
00080 if (ifc->cnt == ifc->max) {
00081 if (ifc->idx) {
00082 ifc->max *= 2;
00083 ifc->idx = realloc(ifc->idx,
00084 sizeof(ifc->idx[0] * ifc->max));
00085 } else {
00086 ifc->max = 8;
00087 ifc->idx = malloc(sizeof(ifc->idx[0] * ifc->max));
00088 }
00089 }
00090 ifc->idx[ifc->cnt++] = idx;
00091 }
00092
00093 static void
00094 _ifrow_to_entry(intf_t *intf, MIB_IFROW *ifrow, struct intf_entry *entry)
00095 {
00096 struct addr *ap, *lap;
00097 int i;
00098
00099 memset(entry, 0, sizeof(*entry));
00100
00101 for (i = 0; i < intf->ifcombo[ifrow->dwType].cnt; i++) {
00102 if (intf->ifcombo[ifrow->dwType].idx[i] == ifrow->dwIndex)
00103 break;
00104 }
00105
00106 snprintf(entry->intf_name, sizeof(entry->intf_name), "%s%lu",
00107 _ifcombo_name(ifrow->dwType), i);
00108 entry->intf_type = (uint16_t)ifrow->dwType;
00109
00110
00111 entry->intf_flags = 0;
00112 if (ifrow->dwAdminStatus == MIB_IF_ADMIN_STATUS_UP)
00113 entry->intf_flags |= INTF_FLAG_UP;
00114 if (ifrow->dwType == MIB_IF_TYPE_LOOPBACK)
00115 entry->intf_flags |= INTF_FLAG_LOOPBACK;
00116 else
00117 entry->intf_flags |= INTF_FLAG_MULTICAST;
00118
00119
00120 entry->intf_mtu = ifrow->dwMtu;
00121
00122
00123 if (ifrow->dwPhysAddrLen == ETH_ADDR_LEN) {
00124 entry->intf_link_addr.addr_type = ADDR_TYPE_ETH;
00125 entry->intf_link_addr.addr_bits = ETH_ADDR_BITS;
00126 memcpy(&entry->intf_link_addr.addr_eth, ifrow->bPhysAddr,
00127 ETH_ADDR_LEN);
00128 }
00129
00130 ap = entry->intf_alias_addrs;
00131 lap = ap + ((entry->intf_len - sizeof(*entry)) /
00132 sizeof(entry->intf_alias_addrs[0]));
00133 for (i = 0; i < (int)intf->iptable->dwNumEntries; i++) {
00134 if (intf->iptable->table[i].dwIndex == ifrow->dwIndex &&
00135 intf->iptable->table[i].dwAddr != 0) {
00136 if (entry->intf_addr.addr_type == ADDR_TYPE_NONE) {
00137
00138 entry->intf_addr.addr_type = ADDR_TYPE_IP;
00139 entry->intf_addr.addr_ip =
00140 intf->iptable->table[i].dwAddr;
00141 addr_mtob(&intf->iptable->table[i].dwMask,
00142 IP_ADDR_LEN, &entry->intf_addr.addr_bits);
00143 } else if (ap < lap) {
00144
00145 ap->addr_type = ADDR_TYPE_IP;
00146 ap->addr_ip = intf->iptable->table[i].dwAddr;
00147 addr_mtob(&intf->iptable->table[i].dwMask,
00148 IP_ADDR_LEN, &ap->addr_bits);
00149 ap++, entry->intf_alias_num++;
00150 }
00151 }
00152 }
00153 entry->intf_len = (u_char *)ap - (u_char *)entry;
00154 }
00155
00156 static int
00157 _refresh_tables(intf_t *intf)
00158 {
00159 MIB_IFROW *ifrow;
00160 ULONG len;
00161 u_int i, ret;
00162
00163
00164 for (len = sizeof(intf->iftable[0]); ; ) {
00165 if (intf->iftable)
00166 free(intf->iftable);
00167 intf->iftable = malloc(len);
00168 ret = GetIfTable(intf->iftable, &len, FALSE);
00169 if (ret == NO_ERROR)
00170 break;
00171 else if (ret != ERROR_INSUFFICIENT_BUFFER)
00172 return (-1);
00173 }
00174
00175 for (len = sizeof(intf->iptable[0]); ; ) {
00176 if (intf->iptable)
00177 free(intf->iptable);
00178 intf->iptable = malloc(len);
00179 ret = GetIpAddrTable(intf->iptable, &len, FALSE);
00180 if (ret == NO_ERROR)
00181 break;
00182 else if (ret != ERROR_INSUFFICIENT_BUFFER)
00183 return (-1);
00184 }
00185
00186
00187
00188
00189 for (i = 0; i < intf->iftable->dwNumEntries; i++) {
00190 ifrow = &intf->iftable->table[i];
00191 if (ifrow->dwType < MIB_IF_TYPE_MAX) {
00192 _ifcombo_add(&intf->ifcombo[ifrow->dwType],
00193 ifrow->dwIndex);
00194 } else
00195 return (-1);
00196 }
00197 return (0);
00198 }
00199
00200 static int
00201 _find_ifindex(intf_t *intf, const char *device)
00202 {
00203 char *p = (char *)device;
00204 int n, type = _ifcombo_type(device);
00205
00206 while (isalpha(*p)) p++;
00207 n = atoi(p);
00208
00209 return (intf->ifcombo[type].idx[n]);
00210 }
00211
00212 intf_t *
00213 intf_open(void)
00214 {
00215 return (calloc(1, sizeof(intf_t)));
00216 }
00217
00218 int
00219 intf_get(intf_t *intf, struct intf_entry *entry)
00220 {
00221 MIB_IFROW ifrow;
00222
00223 if (_refresh_tables(intf) < 0)
00224 return (-1);
00225
00226 ifrow.dwIndex = _find_ifindex(intf, entry->intf_name);
00227
00228 if (GetIfEntry(&ifrow) != NO_ERROR)
00229 return (-1);
00230
00231 _ifrow_to_entry(intf, &ifrow, entry);
00232
00233 return (0);
00234 }
00235
00236 int
00237 intf_get_src(intf_t *intf, struct intf_entry *entry, struct addr *src)
00238 {
00239 MIB_IFROW ifrow;
00240 MIB_IPADDRROW *iprow;
00241 int i;
00242
00243 if (src->addr_type != ADDR_TYPE_IP) {
00244 errno = EINVAL;
00245 return (-1);
00246 }
00247 if (_refresh_tables(intf) < 0)
00248 return (-1);
00249
00250 for (i = 0; i < (int)intf->iptable->dwNumEntries; i++) {
00251 iprow = &intf->iptable->table[i];
00252 if (iprow->dwAddr == src->addr_ip) {
00253 ifrow.dwIndex = iprow->dwIndex;
00254 if (GetIfEntry(&ifrow) != NO_ERROR)
00255 return (-1);
00256 _ifrow_to_entry(intf, &ifrow, entry);
00257 return (0);
00258 }
00259 }
00260 errno = ENXIO;
00261 return (-1);
00262 }
00263
00264 int
00265 intf_get_dst(intf_t *intf, struct intf_entry *entry, struct addr *dst)
00266 {
00267 MIB_IFROW ifrow;
00268
00269 if (dst->addr_type != ADDR_TYPE_IP) {
00270 errno = EINVAL;
00271 return (-1);
00272 }
00273 if (GetBestInterface(dst->addr_ip, &ifrow.dwIndex) != NO_ERROR)
00274 return (-1);
00275
00276 if (GetIfEntry(&ifrow) != NO_ERROR)
00277 return (-1);
00278
00279 if (_refresh_tables(intf) < 0)
00280 return (-1);
00281
00282 _ifrow_to_entry(intf, &ifrow, entry);
00283
00284 return (0);
00285 }
00286
00287 int
00288 intf_set(intf_t *intf, const struct intf_entry *entry)
00289 {
00290
00291
00292
00293
00294
00295 #if 0
00296
00297 if (entry->intf_addr.addr_type == ADDR_TYPE_IP) {
00298 ULONG ctx = 0, inst = 0;
00299 UINT ip, mask;
00300
00301 memcpy(&ip, &entry->intf_addr.addr_ip, IP_ADDR_LEN);
00302 addr_btom(entry->intf_addr.addr_bits, &mask, IP_ADDR_LEN);
00303
00304 if (AddIPAddress(ip, mask,
00305 _find_ifindex(intf, entry->intf_name),
00306 &ctx, &inst) != NO_ERROR) {
00307 return (-1);
00308 }
00309 return (0);
00310 }
00311 #endif
00312 errno = ENOSYS;
00313 SetLastError(ERROR_NOT_SUPPORTED);
00314 return (-1);
00315 }
00316
00317 int
00318 intf_loop(intf_t *intf, intf_handler callback, void *arg)
00319 {
00320 struct intf_entry *entry;
00321 u_char ebuf[1024];
00322 int i, ret = 0;
00323
00324 if (_refresh_tables(intf) < 0)
00325 return (-1);
00326
00327 entry = (struct intf_entry *)ebuf;
00328
00329 for (i = 0; i < (int)intf->iftable->dwNumEntries; i++) {
00330 entry->intf_len = sizeof(ebuf);
00331 _ifrow_to_entry(intf, &intf->iftable->table[i], entry);
00332 if ((ret = (*callback)(entry, arg)) != 0)
00333 break;
00334 }
00335 return (ret);
00336 }
00337
00338 intf_t *
00339 intf_close(intf_t *intf)
00340 {
00341 int i;
00342
00343 if (intf != NULL) {
00344 for (i = 0; i < MIB_IF_TYPE_MAX; i++) {
00345 if (intf->ifcombo[i].idx)
00346 free(intf->ifcombo[i].idx);
00347 }
00348 if (intf->iftable)
00349 free(intf->iftable);
00350 if (intf->iptable)
00351 free(intf->iptable);
00352 free(intf);
00353 }
00354 return (NULL);
00355 }