1 /*
2 get default route (gateway) IPv4 address of the named network
3 interface/adapter (like "eth0").
4
5 This works on both Linux and windows.
6 */
7 #include "rawsock.h"
8 #include "string_s.h"
9 #include "util-malloc.h"
10 #include "massip-parse.h"
11 #include "logger.h"
12
13 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun__)
14 #include <unistd.h>
15 #include <sys/socket.h>
16 #include <net/route.h>
17 #include <netinet/in.h>
18 #include <net/if_dl.h>
19 #include <ctype.h>
20
21 #define ROUNDUP2(a, n) ((a) > 0 ? (1 + (((a) - 1U) | ((n) - 1))) : (n))
22
23 #if defined(__APPLE__)
24 # define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
25 #elif defined(__NetBSD__)
26 # define ROUNDUP(a) ROUNDUP2((a), sizeof(uint64_t))
27 #elif defined(__FreeBSD__)
28 # define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
29 #elif defined(__OpenBSD__)
30 # define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
31 #else
32 # error unknown platform
33 #endif
34
35 static struct sockaddr *
get_rt_address(struct rt_msghdr * rtm,int desired)36 get_rt_address(struct rt_msghdr *rtm, int desired)
37 {
38 int i;
39 int bitmask = rtm->rtm_addrs;
40 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
41
42 for (i = 0; i < RTAX_MAX; i++) {
43 if (bitmask & (1 << i)) {
44 if ((1<<i) == desired)
45 return sa;
46 sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
47 } else
48 ;
49 }
50 return NULL;
51
52 }
53
54 static void
hexdump(const void * v,size_t len)55 hexdump(const void *v, size_t len)
56 {
57 const unsigned char *p = (const unsigned char *)v;
58 size_t i;
59
60
61 for (i=0; i<len; i += 16) {
62 size_t j;
63
64 for (j=i; j<i+16 && j<len; j++)
65 printf("%02x ", p[j]);
66 for (;j<i+16; j++)
67 printf(" ");
68 printf(" ");
69 for (j=i; j<i+16 && j<len; j++)
70 if (isprint(p[j]) && !isspace(p[j]))
71 printf("%c", p[j]);
72 else
73 printf(".");
74 printf("\n");
75 }
76 }
77
78 #if 0
79 #define RTA_DST 0x1 /* destination sockaddr present */
80 #define RTA_GATEWAY 0x2 /* gateway sockaddr present */
81 #define RTA_NETMASK 0x4 /* netmask sockaddr present */
82 #define RTA_GENMASK 0x8 /* cloning mask sockaddr present */
83 #define RTA_IFP 0x10 /* interface name sockaddr present */
84 #define RTA_IFA 0x20 /* interface addr sockaddr present */
85 #define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */
86 #define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */
87 #endif
88
89 void
90 dump_rt_addresses(struct rt_msghdr *rtm);
91
92 void
dump_rt_addresses(struct rt_msghdr * rtm)93 dump_rt_addresses(struct rt_msghdr *rtm)
94 {
95 int i;
96 int bitmask = rtm->rtm_addrs;
97 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
98
99 for (i = 0; i < RTAX_MAX; i++) {
100 if (bitmask & (1 << i)) {
101 printf("b=%u fam=%u len=%u\n", (1<<i), sa->sa_family, sa->sa_len);
102 hexdump(sa, sa->sa_len + sizeof(sa->sa_family));
103 sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
104 } else
105 ;
106 }
107 }
108
109 int
rawsock_get_default_gateway(const char * ifname,unsigned * ipv4)110 rawsock_get_default_gateway(const char *ifname, unsigned *ipv4)
111 {
112 int fd;
113 int seq = (int)time(0);
114 ssize_t err;
115 struct rt_msghdr *rtm;
116 size_t sizeof_buffer;
117
118
119 /*
120 * Requests/responses from the kernel are done with an "rt_msghdr"
121 * structure followed by an array of "sockaddr" structures.
122 */
123 sizeof_buffer = sizeof(*rtm) + 512;
124 rtm = calloc(1, sizeof_buffer);
125
126 /*
127 * Create a socket for querying the kernel
128 */
129 fd = socket(AF_ROUTE, SOCK_RAW, 0);
130 if (fd < 0) {
131 perror("socket(AF_ROUTE)");
132 free(rtm);
133 return errno;
134 }
135
136 /* Needs a timeout. Sometimes it'll hang indefinitely waiting for a
137 * response that will never arrive */
138 {
139 struct timeval timeout;
140 timeout.tv_sec = 1;
141 timeout.tv_usec = 0;
142
143 err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
144 if (err < 0)
145 LOG(0, "[-] SO_RCVTIMEO: %d %s\n", errno, strerror(errno));
146
147 err = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
148 if (err < 0)
149 LOG(0, "[-] SO_SNDTIMEO: %d %s\n", errno, strerror(errno));
150 }
151
152 /*
153 * Format and send request to kernel
154 */
155 rtm->rtm_msglen = sizeof(*rtm) + sizeof(struct sockaddr_in);
156 rtm->rtm_version = RTM_VERSION;
157 rtm->rtm_flags = RTF_UP;
158 rtm->rtm_type = RTM_GET;
159 rtm->rtm_addrs = RTA_DST | RTA_IFP;
160 rtm->rtm_pid = getpid();
161 rtm->rtm_seq = seq;
162
163 /*
164 * Create an empty address of 0.0.0.0 to query the route
165 */
166 {
167 struct sockaddr_in *sin;
168 sin = (struct sockaddr_in *)(rtm + 1);
169 sin->sin_len = sizeof(*sin);
170 sin->sin_family = AF_INET;
171 sin->sin_addr.s_addr = 0;
172 }
173
174 err = write(fd, (char *)rtm, rtm->rtm_msglen);
175 if (err <= 0) {
176 LOG(0, "[-] getroute: write(): returned %d %s\n", errno, strerror(errno));
177 goto fail;
178 }
179
180 /*
181 * Read responses until we find one that belongs to us
182 */
183 for (;;) {
184 err = read(fd, (char *)rtm, sizeof_buffer);
185 if (err <= 0)
186 break;
187 if (rtm->rtm_seq != seq) {
188 printf("seq: %u %u\n", rtm->rtm_seq, seq);
189 continue;
190 }
191 if (rtm->rtm_pid != getpid()) {
192 printf("pid: %u %u\n", rtm->rtm_pid, getpid());
193 continue;
194 }
195 break;
196 }
197 close(fd);
198
199 /*
200 * Parse our data
201 */
202 {
203 struct sockaddr_in *sin;
204 struct sockaddr_dl *sdl;
205
206 sdl = (struct sockaddr_dl *)get_rt_address(rtm, RTA_IFP);
207 if (sdl) {
208 //hexdump(sdl, sdl->sdl_len);
209 //printf("%.*s\n", sdl->sdl_nlen, sdl->sdl_data);
210 if (memcmp(ifname, sdl->sdl_data, sdl->sdl_nlen) != 0) {
211 fprintf(stderr, "ERROR: ROUTE DOESN'T MATCH INTERFACE\n");
212 fprintf(stderr, "YOU'LL HAVE TO SET --router-mac MANUALLY\n");
213 exit(1);
214 }
215 }
216
217 sin = (struct sockaddr_in *)get_rt_address(rtm, RTA_GATEWAY);
218 if (sin) {
219 *ipv4 = ntohl(sin->sin_addr.s_addr);
220 free(rtm);
221 return 0;
222 }
223
224 }
225
226 fail:
227 free(rtm);
228 return -1;
229 }
230
231 #elif defined(__linux__)
232 #include <netinet/in.h>
233 #include <net/if.h>
234 #include <stdio.h>
235 #include <string.h>
236 #include <stdlib.h>
237 #include <unistd.h>
238 #include <sys/socket.h>
239 #include <sys/ioctl.h>
240 #include <linux/netlink.h>
241 #include <linux/rtnetlink.h>
242 #include <sys/types.h>
243 #include <sys/socket.h>
244 #include <arpa/inet.h>
245
246
247
248 struct route_info {
249 struct in_addr dstAddr;
250 struct in_addr srcAddr;
251 struct in_addr gateWay;
252 char ifName[IF_NAMESIZE];
253 };
254
255 static int
read_netlink(int fd,char * bufPtr,size_t sizeof_buffer,int seqNum,int pId)256 read_netlink(int fd, char *bufPtr, size_t sizeof_buffer, int seqNum, int pId)
257 {
258 struct nlmsghdr *nlHdr;
259 int readLen = 0, msgLen = 0;
260
261 do {
262 /* Recieve response from the kernel */
263 if ((readLen = recv(fd, bufPtr, sizeof_buffer - msgLen, 0)) < 0) {
264 perror("SOCK READ: ");
265 return -1;
266 }
267
268 nlHdr = (struct nlmsghdr *) bufPtr;
269
270 /* Check if the header is valid */
271 if ((NLMSG_OK(nlHdr, readLen) == 0)
272 || (nlHdr->nlmsg_type == NLMSG_ERROR)) {
273 perror("Error in received packet");
274 return -1;
275 }
276
277 /* Check if the its the last message */
278 if (nlHdr->nlmsg_type == NLMSG_DONE) {
279 break;
280 } else {
281 /* Else move the pointer to buffer appropriately */
282 bufPtr += readLen;
283 msgLen += readLen;
284 }
285
286 /* Check if its a multi part message */
287 if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0) {
288 /* return if its not */
289 break;
290 }
291 } while ((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pId));
292
293 return msgLen;
294 }
295
296 /* For parsing the route info returned */
297 static int
parseRoutes(struct nlmsghdr * nlHdr,struct route_info * rtInfo)298 parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo)
299 {
300 struct rtmsg *rtMsg;
301 struct rtattr *rtAttr;
302 int rtLen = 0;
303
304 rtMsg = (struct rtmsg *) NLMSG_DATA(nlHdr);
305
306 /* This must be an IPv4 (AF_INET) route */
307 if (rtMsg->rtm_family != AF_INET)
308 return 1;
309
310 /* This must be in main routing table */
311 if (rtMsg->rtm_table != RT_TABLE_MAIN)
312 return 1;
313
314 /* Attributes field*/
315 rtAttr = (struct rtattr *)RTM_RTA(rtMsg);
316 rtLen = RTM_PAYLOAD(nlHdr);
317 for (; RTA_OK(rtAttr, rtLen); rtAttr = RTA_NEXT(rtAttr, rtLen)) {
318 switch (rtAttr->rta_type) {
319 case RTA_OIF:
320 if_indextoname(*(int *) RTA_DATA(rtAttr), rtInfo->ifName);
321 break;
322 case RTA_GATEWAY:
323 rtInfo->gateWay.s_addr = *(u_int *)RTA_DATA(rtAttr);
324 break;
325 case RTA_PREFSRC:
326 rtInfo->srcAddr.s_addr = *(u_int *)RTA_DATA(rtAttr);
327 break;
328 case RTA_DST:
329 rtInfo->dstAddr .s_addr = *(u_int *)RTA_DATA(rtAttr);
330 break;
331 }
332 }
333
334 return 0;
335 }
336
337
rawsock_get_default_gateway(const char * ifname,unsigned * ipv4)338 int rawsock_get_default_gateway(const char *ifname, unsigned *ipv4)
339 {
340 int fd;
341 struct nlmsghdr *nlMsg;
342 char msgBuf[16384];
343 int len;
344 int msgSeq = 0;
345
346 /*
347 * Set to zero, in case we cannot find it
348 */
349 *ipv4 = 0;
350
351 /*
352 * Create 'netlink' socket to query kernel
353 */
354 fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
355 if (fd < 0) {
356 fprintf(stderr, "%s:%d: socket(NETLINK_ROUTE): %d\n",
357 __FILE__, __LINE__, errno);
358 return errno;
359 }
360
361 /*
362 * format the netlink buffer
363 */
364 memset(msgBuf, 0, sizeof(msgBuf));
365 nlMsg = (struct nlmsghdr *)msgBuf;
366
367 nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
368 nlMsg->nlmsg_type = RTM_GETROUTE;
369 nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
370 nlMsg->nlmsg_seq = msgSeq++;
371 nlMsg->nlmsg_pid = getpid();
372
373 /*
374 * send first request to kernel
375 */
376 if (send(fd, nlMsg, nlMsg->nlmsg_len, 0) < 0) {
377 fprintf(stderr, "%s:%d: send(NETLINK_ROUTE): %d\n",
378 __FILE__, __LINE__, errno);
379 return errno;
380 }
381
382 /*
383 * Now read all the responses
384 */
385 len = read_netlink(fd, msgBuf, sizeof(msgBuf), msgSeq, getpid());
386 if (len <= 0) {
387 fprintf(stderr, "%s:%d: read_netlink: %d\n",
388 __FILE__, __LINE__, errno);
389 return errno;
390 }
391
392
393 /*
394 * Parse the response
395 */
396 for (; NLMSG_OK(nlMsg, len); nlMsg = NLMSG_NEXT(nlMsg, len)) {
397 struct route_info rtInfo[1];
398 int err;
399
400 memset(rtInfo, 0, sizeof(struct route_info));
401
402 err = parseRoutes(nlMsg, rtInfo);
403 if (err != 0)
404 continue;
405
406 /* make sure we match the desired network interface */
407 if (ifname && strcmp(rtInfo->ifName, ifname) != 0)
408 continue;
409
410 /* make sure destination = 0.0.0.0 for "default route" */
411 if (rtInfo->dstAddr.s_addr != 0)
412 continue;
413
414 /* found the gateway! */
415 *ipv4 = ntohl(rtInfo->gateWay.s_addr);
416 }
417
418 close(fd);
419
420 return 0;
421 }
422
423 #endif
424
425
426 #if defined(WIN32)
427 #include <winsock2.h>
428 #include <iphlpapi.h>
429 #ifdef _MSC_VER
430 #pragma comment(lib, "IPHLPAPI.lib")
431 #endif
432
433
434
rawsock_get_default_gateway(const char * ifname,unsigned * ipv4)435 int rawsock_get_default_gateway(const char *ifname, unsigned *ipv4)
436 {
437 PIP_ADAPTER_INFO pAdapterInfo;
438 PIP_ADAPTER_INFO pAdapter = NULL;
439 DWORD err;
440 ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
441
442 /*
443 * Translate numeric index (if it exists) to real name
444 */
445 ifname = rawsock_win_name(ifname);
446 //printf("------ %s -----\n", ifname);
447
448 /*
449 * Allocate a proper sized buffer
450 */
451 pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof (IP_ADAPTER_INFO));
452 if (pAdapterInfo == NULL) {
453 fprintf(stderr, "Error allocating memory needed to call GetAdaptersinfo\n");
454 return EFAULT;
455 }
456
457 /*
458 * Query the adapter info. If the buffer is not big enough, loop around
459 * and try again
460 */
461 again:
462 err = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
463 if (err == ERROR_BUFFER_OVERFLOW) {
464 free(pAdapterInfo);
465 pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
466 if (pAdapterInfo == NULL) {
467 fprintf(stderr, "Error allocating memory needed to call GetAdaptersinfo\n");
468 return EFAULT;
469 }
470 goto again;
471 }
472 if (err != NO_ERROR) {
473 fprintf(stderr, "GetAdaptersInfo failed with error: %u\n",
474 (unsigned)err);
475 return EFAULT;
476 }
477
478 /*
479 * loop through all adapters looking for ours
480 */
481 for ( pAdapter = pAdapterInfo;
482 pAdapter;
483 pAdapter = pAdapter->Next) {
484 if (rawsock_is_adapter_names_equal(pAdapter->AdapterName, ifname))
485 break;
486 }
487
488 if (pAdapter) {
489 //printf("\tComboIndex: \t%d\n", pAdapter->ComboIndex);
490 //printf("\tAdapter Name: \t%s\n", pAdapter->AdapterName);
491 //printf("\tAdapter Desc: \t%s\n", pAdapter->Description);
492
493
494 //printf("\tAdapter Addr: \t");
495 /*for (i = 0; i < pAdapter->AddressLength; i++) {
496 if (i == (pAdapter->AddressLength - 1))
497 printf("%.2X\n", (int) pAdapter->Address[i]);
498 else
499 printf("%.2X-", (int) pAdapter->Address[i]);
500 }*/
501 //printf("\tIndex: \t%d\n", pAdapter->Index);
502 //printf("\tType: \t");
503 switch (pAdapter->Type) {
504 case MIB_IF_TYPE_OTHER:
505 //printf("Other\n");
506 break;
507 case MIB_IF_TYPE_ETHERNET:
508 //printf("Ethernet\n");
509 break;
510 case MIB_IF_TYPE_TOKENRING:
511 //printf("Token Ring\n");
512 break;
513 case MIB_IF_TYPE_FDDI:
514 //printf("FDDI\n");
515 break;
516 case MIB_IF_TYPE_PPP:
517 //printf("PPP\n");
518 break;
519 case MIB_IF_TYPE_LOOPBACK:
520 //printf("Lookback\n");
521 break;
522 case MIB_IF_TYPE_SLIP:
523 //printf("Slip\n");
524 break;
525 default:
526 //printf("Unknown type %ld\n", pAdapter->Type);
527 break;
528 }
529
530 //printf("\tIP Address: \t%s\n", pAdapter->IpAddressList.IpAddress.String);
531 //printf("\tIP Mask: \t%s\n", pAdapter->IpAddressList.IpMask.String);
532
533 /*typedef struct _IP_ADDR_STRING {
534 struct _IP_ADDR_STRING* Next;
535 IP_ADDRESS_STRING IpAddress;
536 IP_MASK_STRING IpMask;
537 DWORD Context;
538 } IP_ADDR_STRING, *PIP_ADDR_STRING;*/
539
540 {
541 const IP_ADDR_STRING *addr;
542
543 for (addr = &pAdapter->GatewayList; addr; addr = addr->Next) {
544 unsigned x = massip_parse_ipv4(addr->IpAddress.String);
545 if (x != 0xFFFFFFFF) {
546 *ipv4 = x;
547 goto end;
548 }
549 }
550 }
551
552
553 //printf("\n");
554 }
555 end:
556 if (pAdapterInfo)
557 free(pAdapterInfo);
558 return 0;
559 }
560
561 #endif
562