linux raw sock发送RS报文

来源:互联网 发布:不会算法的程序员 编辑:程序博客网 时间:2024/06/15 09:51

旨在解决内核不主动发IPV6的router solicit报文问题,手动发

1./*2. * use special interface to send ipv6 router solicit packet3. * leon, 2017-6-28 15:22:114. */5.6.#include <stdio.h>7.#include <string.h>8.#include <stdlib.h>9.#include <unistd.h>10.#include <sys/types.h>11.#include <sys/socket.h>12.#include <fcntl.h>13.#include <sys/ioctl.h>14.15.#include <netdb.h> /* getaddrinfo() */16.#include <arpa/inet.h> /* inet_ntop() */17.#include <net/if.h> /* if_nametoindex() */18.19.#include <netinet/in.h>20.#include <netdb.h>21.#include "ifaddrs.h"22.#include <netinet/icmp6.h>23.24.typedef struct25.{26.    struct nd_router_solicit hdr;27.    struct nd_opt_hdr opt;28.    uint8_t hw_addr[6];29.} solicit_packet;30.31.static int get_mac_address(const char *ifname, uint8_t *addr)32.{33.    struct ifreq req;34.    memset(&req, 0, sizeof (req));35.36.    if(((unsigned)strlen(ifname)) >= (unsigned)IFNAMSIZ)37.        return -1; /* buffer overflow = local root */38.    strcpy(req.ifr_name, ifname);39.40.    int fd = socket(AF_INET6, SOCK_DGRAM, 0);41.    if (fd == -1)42.        return -1;43.44.    if (ioctl(fd, SIOCGIFHWADDR, &req))45.    {46.        perror(ifname);47.        close(fd);48.        return -1;49.    }50.    close(fd);51.52.    memcpy(addr, req.ifr_hwaddr.sa_data, 6);53.54.    /* ppp interface maybe get zero mac address */55.    uint8_t zero_mac[6] = {0};56.    if(!memcmp(addr, zero_mac, sizeof(zero_mac)))57.        return -1;58.59.    return 0;60.}61.62.63.int get_if_link_local_addr6(char *ifname, struct sockaddr_in6 *addr6)64.{   65.    struct ifaddrs *ifaddr, *ifa;   66.    char ip_str[64];67.    struct in6_addr *tmp;68.    int ok = 0;69.70.    if(!ifname || !addr6)71.        return 0;72.73.    if (-1 == getifaddrs(&ifaddr))74.    {75.        perror("getifaddrs");76.        return; 77.    }78.79.    for(ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) 80.    {       81.        if(ifa->ifa_name && !strcmp(ifa->ifa_name, ifname) && 82.            ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6)83.        {   84.            tmp = &((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_addr;85.            if(IN6_IS_ADDR_LINKLOCAL(tmp))86.            {87.                memcpy(addr6, ifa->ifa_addr, sizeof(struct sockaddr_in6)); 88.                ok = 1;89.                //inet_ntop(AF_INET6, tmp, ip_str, sizeof(ip_str));90.                //printf("%s\n", ip_str);91.            }92.        }93.    }   94.    freeifaddrs(ifaddr);  95.    if(!ok)96.    {97.        printf("Not find the interface(%s) address\n", ifname);98.        return -1;99.    }    100.    return 0;101.}102.103.104.ssize_t build_rs(solicit_packet *rs, const char *ifname)105.{106.    /* builds ICMPv6 Router Solicitation packet */107.    rs->hdr.nd_rs_type = ND_ROUTER_SOLICIT;108.    rs->hdr.nd_rs_code = 0;109.    rs->hdr.nd_rs_cksum = 0; /* computed by the kernel */110.    rs->hdr.nd_rs_reserved = 0;111.112.    /* gets our own interface's link-layer address (MAC) */113.    if (get_mac_address(ifname, rs->hw_addr))114.        return sizeof(rs->hdr);115.116.    rs->opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;117.    rs->opt.nd_opt_len = 1; /* 8 bytes */118.119.    return sizeof(*rs);120.}121.122.int main(int argc, char *argv[])123.{124.    int s = -1;125.    struct sockaddr_in6 src;126.    solicit_packet packet;127.    struct sockaddr_in6 dst;128.    char *ifname = NULL;129.    ssize_t plen;130.131.    if(argc < 2)132.    {133.        printf("usage: %s [ifname]\n", argv[0]);134.        return -1;135.    }136.    ifname = argv[1];137.138.    s = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);139.    if(-1 == s)140.    {141.        perror("socket create");142.        return -1;143.    }144.145.    get_if_link_local_addr6(ifname, &src);146.    if(-1 == bind(s, (struct sockaddr *)&src, sizeof(src)))147.    {148.        perror("bind");149.        close(s);150.        return -1;151.    }152.153.    memcpy(&dst, &src, sizeof (dst));  /* copy some address info */154.    memcpy(dst.sin6_addr.s6_addr, "\xff\x02\x00\x00\x00\x00\x00\x00"155.                                    "\x00\x00\x00\x00\x00\x00\x00\x02", 16);156.157.    plen = build_rs(&packet, ifname);158.    if (sendto(s, &packet, plen, 0, (const struct sockaddr *)&dst, sizeof(dst)) != plen)159.    {160.        perror("Sending ICMPv6 packet");161.        close(s);162.        return -1;163.    }164.165.    return 0;166.}

ubuntu 15.04下测试OK

ARM交叉编译时,提示没有ifaddrs.h文件,需要自己添加ifaddrs.c和ifaddrs.h,然后一起编译,测试OK。

原创粉丝点击