main.c

#include <arp.h>

#define ARP_BEGIN(dst,src,if) printf("ARPING %s from %s %s\n",dst,src,if);

static void printHelp(char *);
static int arp_get_options(int, char **,char *, char *);

int main(int argc, char **argv) {
    char ifname[IF_NAMESIZE];
    char dstaddr[IF_NAMESIZE];
    struct ifi_rinfo *rinfo;
    struct sockaddr_ll peer_addr;
    int sockfd;
    memset(ifname, 0, IF_NAMESIZE);
    memset(dstaddr, 0, IF_NAMESIZE);
    // 解析参数
    if (arp_get_options(argc, argv, ifname, dstaddr) < 0) {
        return ARP_ERROR;
    }
    // 获取接口信息
    if ((rinfo=get_ifi_rinfo(ifname)) == NULL) {
        return ARP_ERROR;
    }
    // 检查接口是否支持arp包
    if (check_flags(rinfo) < 0) {
        return ARP_ERROR;
    }
    // 创建AF_PACKET套接字
    if( (sockfd = sockraw(0)) < 0) {
        return ARP_ERROR;
    }
    // 初始化发送信息
    memset(&peer_addr, 0, sizeof(struct sockaddr_ll));
    peer_addr.sll_family = AF_PACKET;
    peer_addr.sll_ifindex = rinfo->ifindex;

    ARP_BEGIN(dstaddr, rinfo->ipaddr_str, ifname);
    // 发送arp报文
    arp_send(sockfd, rinfo, dstaddr, &peer_addr);
    // 接收arp报文
    arp_recv(sockfd, rinfo, dstaddr);
    // 关闭套接字
    free(rinfo);
    close(sockfd);
    return 0;
}

/*
* 打印帮助
*/
static void printHelp(char *progName) {
    printf("welcome use %s program, version is v%s\n", progName, ARP_VERSION);
    printf("usage:\t");
    printf("%s -I interface host\n", progName);
}

/*
* 获取参数
*/
static int arp_get_options(int argc, char **argv, char *ifname, char *dstaddr) {
    if (argc < 2) {
        printHelp(argv[0]);
        return ARP_ERROR;
    }
    int ch;
    opterr = 1; // 将错误打开
    while((ch = getopt(argc, argv, "I:")) != -1) {
        switch (ch) {
            case 'I':
                strcpy(ifname, optarg);
                break;
            case '?':
                printHelp(argv[0]);
                return ARP_ERROR;
        }
    }
    if(ifname[0] == '\0'){
        printHelp(argv[0]);
        return ARP_ERROR;
    }
    // 没有操作数情况
    if (optind != argc-1){
          printHelp(argv[0]);
          return ARP_ERROR;  
    }
    strcpy(dstaddr, argv[optind]);
    return ARP_OK;
}

主流程

  1. 解析参数
  2. 根据传入的接口名字得到接口信息
  3. 检查接口是否支持发送arp
  4. 创建AF_PACKET 原始套接字
  5. 初始化链路层struct sockaddr_ll结构的套接字地址信息
  6. 打印开始字符串
  7. 发送arp报文
  8. 接收arp响应报文
    1. 循环读取
    • 判断发送者IP地址是否为原目标地址
    • 判断接收者IP地址是否为接口ip地址
    • 判断是否为arp 响应报文
    • 判断是单播还会多播,输出相应字符串到stdout
    • 如果不满足条件则继续循环读取
    1. 如果读取时间超过指定时间,则退出
  9. 回收内存和关闭套接字
文档更新时间: 2021-02-04 19:34   作者:周国强