2010-07-20 18 views
15

Tôi đã nhìn xung quanh như điên nhưng không nhận được câu trả lời thực sự. Tôi có một ví dụ, nhưng điều đó phụ thuộc vào thư viện của cá nhân nên không tốt lắm. Lúc đầu, tôi muốn có cổng mặc định của một giao diện, nhưng vì các IP khác nhau có thể được định tuyến khác nhau nên tôi nhanh chóng hiểu rằng tôi muốn nó có cổng để sử dụng cho một IP đích bằng cách sử dụng một ổ cắm AF_ROUTErtm_type RTM_GET. Có ai có một ví dụ mà tôi thực sự kết thúc với một chuỗi có chứa các cổng IP (hoặc địa chỉ mac)? Mục nhập cổng có vẻ là hex nhưng cũng được mã hóa trong/proc/net/route, nơi tôi đoán cổng thông tin AF_ROUTE lấy thông tin từ (nhưng thông qua hạt nhân tôi đoán).Nhận cổng để sử dụng cho một ip đã cho trong ANSI C

Thanx trước

và p.s. Tôi chỉ mới bắt đầu sử dụng tràn ngăn xếp và tôi phải nói, tất cả các bạn đều tuyệt vời! Trả lời nhanh và những câu trả lời hay! Bạn là những người bạn thân nhất của tôi;)

Trả lời

16

Đây là hệ điều hành cụ thể, không có API thống nhất (hoặc ANSI C) nào cho điều này.

Giả sử Linux, cách tốt nhất là phân tích cú pháp/proc/net/route, tìm mục nhập đích đến 00000000, cổng mặc định nằm trong cột Cổng, nơi bạn có thể đọc biểu diễn hex của cổng IP giải quyết (trong cuối lớn, tôi tin)

Nếu bạn muốn làm điều này qua các cuộc gọi API cụ thể hơn, bạn sẽ phải trải qua khá một số hoops, đây là một chương trình ví dụ:

#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; 
} 
+0

Ví dụ làm việc tuyệt vời; cảm ơn. Trong khi điều này chỉ cung cấp cổng IPv4, nó cũng có thể được tinh chỉnh để tìm cổng IPv6 (nếu ai đó tò mò muốn biết). – jdknight

2

tôi quyết định để đi theo cách "nhanh chóng và bẩn" để bắt đầu và đọc ip từ /proc/net/route bằng cách sử dụng netstat -rm.

Tôi nghĩ rằng tôi muốn chia sẻ chức năng của mình ... Lưu ý rằng có một số lỗi trong đó và bạn có thể giúp tôi tìm và tôi sẽ sửa lỗi này mà không bị lỗi. Hàm này lấy tên iface như eth0 và trả về ip của cổng được sử dụng bởi iface đó.

char* GetGatewayForInterface(const char* interface) { 
    char* gateway = NULL; 

    FILE* fp = popen("netstat -rn", "r"); 
    char line[256]={0x0}; 

    while(fgets(line, sizeof(line), fp) != NULL) 
    {  
    /* 
    * Get destination. 
    */ 
    char* destination; 
    destination = strndup(line, 15); 

    /* 
    * Extract iface to compare with the requested one 
    * todo: fix for iface names longer than eth0, eth1 etc 
    */ 
    char* iface; 
    iface = strndup(line + 73, 4); 


    // Find line with the gateway 
    if(strcmp("0.0.0.0  ", destination) == 0 && strcmp(iface, interface) == 0) { 
     // Extract gateway 
     gateway = strndup(line + 16, 15); 
    } 

    free(destination); 
    free(iface); 
    } 

    pclose(fp); 
    return gateway; 
} 

Vấn đề với chức năng này là khi tôi để máy tính ở đó, nó gây ra hỏng hóc hỏng bộ nhớ. Nhưng nó hoạt động nếu tôi loại bỏ các cuộc gọi pclose (nhưng đó sẽ không phải là một giải pháp tốt beacuse dòng sẽ vẫn mở .. hehe). Vì vậy, nếu bất cứ ai có thể phát hiện lỗi, tôi sẽ chỉnh sửa chức năng với phiên bản chính xác. Tôi không có C guru và có chút bối rối về tất cả bộ nhớ khó hiểu;)

+0

Không có gì trong mã bạn đã đăng sẽ gây ra sự cố tham nhũng bộ nhớ. Tôi xác nhận rằng bằng cách chạy nó với valgrind. – indiv

4

Có lẽ đây là câu hỏi rất cũ nhưng tôi có cùng một vấn đề và tôi không thể tìm thấy kết quả tốt hơn. Cuối cùng tôi đã giải quyết được vấn đề của mình với những mã này mà nó có một vài thay đổi. Vì vậy, tôi quyết định chia sẻ nó.

char* GetGatewayForInterface(const char* interface) 
{ 
    char* gateway = NULL; 

    char cmd [1000] = {0x0}; 
    sprintf(cmd,"route -n | grep %s | grep 'UG[ \t]' | awk '{print $2}'", interface); 
    FILE* fp = popen(cmd, "r"); 
    char line[256]={0x0}; 

    if(fgets(line, sizeof(line), fp) != NULL) 
     gateway = string(line); 


    pclose(fp); 
} 
Các vấn đề liên quan