Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting gateway to use for a given ip in ANSI C

Tags:

I have looked around like crazy but don't get a real answer. I got one example, but that depended on the individuals own library so not much good.

At first I wanted to get the default gateway of an interface, but since different IP's could be routed differently I quickly understood that what I want it get the gateway to use for a given destination IP by using an AF_ROUTE socket and the rtm_type RTM_GET. Does anyone have an example where I actually end up with a string containing the gateways IP (or mac address)? The gateway entry seem to be in hex but also encoded in /proc/net/route, where I guess the AF_ROUTE socket get's it info from (but via the kernel I guess).

Thanx in advance

and p.s. I just started using stack overflow and I must say, all of you guys are great! Fast replies and good ones! You are my new best friends ;)

like image 242
inquam Avatar asked Jul 20 '10 08:07

inquam


People also ask

How do I use default gateway for IP address?

To configure the default gateway for the switch, use the ip default-gateway command. Enter the IP address of the default gateway. The default gateway is the IP address of the router interface to which the switch is connected. Use the copy running-config startup-config command to back up your configuration.

Does the gateway have to match the IP address?

A default gateway is the node in a computer network using the Internet protocol suite that serves as the forwarding host (router) to other networks when no other route specification matches the destination IP address of a packet.

How do I know what default gateway to use?

In the Command Prompt window, type “ipconfig” and press “Enter/Return” on your keyboard. You will see a lot of information generated in this window. If you scroll up you should see “Default Gateway” with the device's IP address listed to the right of it.

Can default gateway be any IP address?

The default gateway always resides in the same subnet as the end device IP. The gateway can really be any unique address within the subnet itself, but most network administrators designate the first number of the subnet as the gateway.


1 Answers

This is OS specific, there's no unified(or ANSI C) API for this.

Assuming Linux, the best way is to just parse /proc/net/route , look for the entry where Destination is 00000000 , the default gateway is in the Gateway column , where you can read the hex representation of the gateway IP address (in big endian , I believe)

If you want to do this via more specific API calls, you'll have to go through quite some hoops, here's an example program:

#include <netinet/in.h> #include <net/if.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h>   #define BUFSIZE 8192 char gateway[255];  struct route_info {     struct in_addr dstAddr;     struct in_addr srcAddr;     struct in_addr gateWay;     char ifName[IF_NAMESIZE]; };  int readNlSock(int sockFd, char *bufPtr, int seqNum, int pId) {     struct nlmsghdr *nlHdr;     int readLen = 0, msgLen = 0;   do {     /* Recieve response from the kernel */         if ((readLen = recv(sockFd, bufPtr, BUFSIZE - msgLen, 0)) < 0) {             perror("SOCK READ: ");             return -1;         }          nlHdr = (struct nlmsghdr *) bufPtr;      /* Check if the header is valid */         if ((NLMSG_OK(nlHdr, readLen) == 0)             || (nlHdr->nlmsg_type == NLMSG_ERROR)) {             perror("Error in recieved packet");             return -1;         }      /* Check if the its the last message */         if (nlHdr->nlmsg_type == NLMSG_DONE) {             break;         } else {     /* Else move the pointer to buffer appropriately */             bufPtr += readLen;             msgLen += readLen;         }      /* Check if its a multi part message */         if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0) {            /* return if its not */             break;         }     } while ((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pId));     return msgLen; } /* For printing the routes. */ void printRoute(struct route_info *rtInfo) {     char tempBuf[512];  /* Print Destination address */     if (rtInfo->dstAddr.s_addr != 0)         strcpy(tempBuf,  inet_ntoa(rtInfo->dstAddr));     else         sprintf(tempBuf, "*.*.*.*\t");     fprintf(stdout, "%s\t", tempBuf);  /* Print Gateway address */     if (rtInfo->gateWay.s_addr != 0)         strcpy(tempBuf, (char *) inet_ntoa(rtInfo->gateWay));     else         sprintf(tempBuf, "*.*.*.*\t");     fprintf(stdout, "%s\t", tempBuf);      /* Print Interface Name*/     fprintf(stdout, "%s\t", rtInfo->ifName);      /* Print Source address */     if (rtInfo->srcAddr.s_addr != 0)         strcpy(tempBuf, inet_ntoa(rtInfo->srcAddr));     else         sprintf(tempBuf, "*.*.*.*\t");     fprintf(stdout, "%s\n", tempBuf); }  void printGateway() {     printf("%s\n", gateway); } /* For parsing the route info returned */ void parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo) {     struct rtmsg *rtMsg;     struct rtattr *rtAttr;     int rtLen;      rtMsg = (struct rtmsg *) NLMSG_DATA(nlHdr);  /* If the route is not for AF_INET or does not belong to main routing table then return. */     if ((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN))         return;  /* get the rtattr field */     rtAttr = (struct rtattr *) RTM_RTA(rtMsg);     rtLen = RTM_PAYLOAD(nlHdr);     for (; RTA_OK(rtAttr, rtLen); rtAttr = RTA_NEXT(rtAttr, rtLen)) {         switch (rtAttr->rta_type) {         case RTA_OIF:             if_indextoname(*(int *) RTA_DATA(rtAttr), rtInfo->ifName);             break;         case RTA_GATEWAY:             rtInfo->gateWay.s_addr= *(u_int *) RTA_DATA(rtAttr);             break;         case RTA_PREFSRC:             rtInfo->srcAddr.s_addr= *(u_int *) RTA_DATA(rtAttr);             break;         case RTA_DST:             rtInfo->dstAddr .s_addr= *(u_int *) RTA_DATA(rtAttr);             break;         }     }     //printf("%s\n", inet_ntoa(rtInfo->dstAddr));      if (rtInfo->dstAddr.s_addr == 0)         sprintf(gateway, (char *) inet_ntoa(rtInfo->gateWay));     //printRoute(rtInfo);      return; }   int main() {     struct nlmsghdr *nlMsg;     struct rtmsg *rtMsg;     struct route_info *rtInfo;     char msgBuf[BUFSIZE];      int sock, len, msgSeq = 0;  /* Create Socket */     if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)         perror("Socket Creation: ");      memset(msgBuf, 0, BUFSIZE);  /* point the header and the msg structure pointers into the buffer */     nlMsg = (struct nlmsghdr *) msgBuf;     rtMsg = (struct rtmsg *) NLMSG_DATA(nlMsg);  /* Fill in the nlmsg header*/     nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));  // Length of message.     nlMsg->nlmsg_type = RTM_GETROUTE;   // Get the routes from kernel routing table .      nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;    // The message is a request for dump.     nlMsg->nlmsg_seq = msgSeq++;    // Sequence of the message packet.     nlMsg->nlmsg_pid = getpid();    // PID of process sending the request.  /* Send the request */     if (send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0) {         printf("Write To Socket Failed...\n");         return -1;     }  /* Read the response */     if ((len = readNlSock(sock, msgBuf, msgSeq, getpid())) < 0) {         printf("Read From Socket Failed...\n");     return -1;     } /* Parse and print the response */     rtInfo = (struct route_info *) malloc(sizeof(struct route_info)); //fprintf(stdout, "Destination\tGateway\tInterface\tSource\n");     for (; NLMSG_OK(nlMsg, len); nlMsg = NLMSG_NEXT(nlMsg, len)) {         memset(rtInfo, 0, sizeof(struct route_info));         parseRoutes(nlMsg, rtInfo);     }     free(rtInfo);     close(sock);      printGateway();     return 0; } 
like image 112
nos Avatar answered Sep 23 '22 18:09

nos