花开的时候我们还在没等到花儿凋零

tap 转发数据包

Correct·2022-08-31 09:43·285 次阅读

tap 转发数据包

1、打开tap虚拟网卡#

我将它封装在了一个函数opentap中,如下所示

int open_tap(const char *dev, short flags) {
    struct ifreq ifr;
    int fd, err;
    char *device = "/dev/net/tun";
    if ((fd = open(device, O_RDWR)) < 0) {
        printf("[ERROR|%s|Cannot open TUN/TAP dev %d]\n", __TIME__, __LINE__);
        exit(0);
    }
    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_ifru.ifru_flags |= flags;
    if (dev != NULL && (*dev) != '\0') {
        strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ);
    }
    if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
        close(fd);
        return err;
    }
    return fd;
}

2、关闭防火墙,设置iptables策略,将流量导向tap网卡

# 关闭防火墙
systemctl stop ufw
systemctl disable ufw

# 开启转发
echo 1 > /proc/sys/net/ipv4/ip_forward
# 或者在/etc/sysctl.conf文件中加入一行(永久生效)

# 设置iptables
iptables -t nat -A PREROUTING -i ens33 -d 192.168.13.147 -p tcp --dport 1234 -j DNAT --to 10.0.1.123:6666
# 将从ens33来的目标地址为192.168.13.147且目的端口号为1234的tcp数据包做nat

iptables -t nat -A POSTROUTING --dst 10.0.1.123 -p tcp --dport 6666 -j SNAT --to-source 192.168.13.147
# 将目标地址为10.0.1.123、目的端口号为6666的tcp数据包做nat

# 此时tap网卡的ip地址为10.0.1.111
# 10.0.1.123和tap虚拟网卡在同一网段,因此会收到arp请求,询问10.0.1.123的mac地址
# 添加一条静态的arp条目
arp -s 10.0.1.123 xx:xx:xx:xx:xx:xx

通过工具从192.168.13.1向192.168.13.147发udp数据包

然后通过wireshark抓包就可以看到tap网卡有流量经过了

相应地,192.168.13.1也收到了回包

3、代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <linux/if_tun.h>
#include <net/if.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>

int open_tap(const char *dev, short flags) {
    struct ifreq ifr;
    int fd, err;
    char *device = "/dev/net/tun";
    if ((fd = open(device, O_RDWR)) < 0) {
        printf("[ERROR|%s|Cannot open TUN/TAP dev %d]\n", __TIME__, __LINE__);
        exit(0);
    }
    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_ifru.ifru_flags |= flags;
    if (dev != NULL && (*dev) != '\0') {
        strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ);
    }
    if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
        close(fd);
        return err;
    }
    return fd;
}

static u_int16_t checksum(u_int16_t *address, int count) {
    long sum = 0;
    while (count > 1) {
        sum += *(ushort *)address++;
        count -= 2;
    }
    if (count > 0) {
        sum += *(u_char *)address;
    }
    while (sum >> 16) {
        sum = (sum & 0xffff) + (sum >> 16);
    }
    return ~sum;
}

unsigned short check_sum(unsigned short *data, int num){
    unsigned long sum = 0;
    for(int i = 0;i < num; i++){
        sum += *data++;	//将2个16进制数相加
        sum = (sum>>16) + (sum&0xffff); //取相加结果的低16位与高16位相加
    }
    return ~sum;	//对最后的结果取反
}

struct udp_hdr {
    u_int16_t src_port;
    u_int16_t dest_port;
    u_int16_t len;
    u_int16_t checksum;
} __attribute__((__packed__));

struct icmp_hdr {
    u_int8_t icmp_type;
    u_int8_t icmp_code;
    u_int16_t icmp_cksum;
    u_int16_t icmp_ident;
    u_int16_t icmp_seq_nb;
} __attribute__((__packed__));

struct ipv4_hdr {
    __extension__
    union {
        u_int8_t version_ihl;    /**< version and header length */
        struct {
#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
            u_int8_t ihl:4;     /**< header length */
            u_int8_t version:4; /**< version */
#elif RTE_BYTE_ORDER == RTE_BIG_ENDIAN
            uint8_t version:4; /**< version */
			uint8_t ihl:4;     /**< header length */
#endif
        };
    };
    u_int8_t  type_of_service;	/**< type of service */
    u_int16_t total_length;	/**< length of packet */
    u_int16_t packet_id;		/**< packet ID */
    u_int16_t fragment_offset;	/**< fragmentation offset */
    u_int8_t  time_to_live;		/**< time to live */
    u_int8_t  next_proto_id;		/**< protocol ID */
    u_int16_t hdr_checksum;	/**< header checksum */
    u_int32_t src_addr;		/**< source address */
    u_int32_t dst_addr;		/**< destination address */
} __attribute__((__packed__));

struct ether_addr {
    u_int8_t addr_bytes[6]; /**< Addr bytes in tx order */
} __attribute__((__aligned__(2)));

struct ether_hdr {
    struct ether_addr dst_addr; /**< Destination address. */
    struct ether_addr src_addr; /**< Source address. */
    u_int16_t ether_type; /**< Frame type. */
} __attribute__((__aligned__(2)));


int main() {
    int tap;
    long int ret;
    char tap_name[IFNAMSIZ];
    unsigned char buf[4096];
    sprintf(tap_name, "tap1");
    tap = open_tap(tap_name, IFF_TAP | IFF_NO_PI);
//    tap = open_tap(tap_name, IFF_TUN | IFF_NO_PI);
    if (tap < 0) {
        printf("[ERROR|%s|Cannot open TUN/TAP dev %d]\n", __TIME__, __LINE__);
        exit(0);
    }
    char *cmd = (char *)malloc(sizeof(char) * 60);
    snprintf(cmd, 60, "ifconfig %s 10.0.1.111", tap_name);
    printf("[DEBUG|%s|line:%d|cmd:%s %d]\n", __TIME__, __LINE__, cmd, system(cmd));
    free(cmd);
    while (1) {
        ret = read(tap, buf, sizeof(buf));
        printf("%ld\n", ret);
        ssize_t len = ret;
        if (ret <= 0) continue;
        struct ether_hdr *ether = (struct ether_hdr *)(buf);
        struct ipv4_hdr *ip = (struct ipv4_hdr *)(buf + sizeof(struct ether_hdr));

        struct udp_hdr *udp = (struct udp_hdr *)(buf + sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr));
        udp->checksum = 0;

        ip->dst_addr ^= ip->src_addr;
        ip->src_addr ^= ip->dst_addr;
        ip->dst_addr ^= ip->src_addr;
        ip->hdr_checksum = 0;
        ip->hdr_checksum = checksum((u_int16_t *)ip, ip->ihl * 4);

        struct ether_addr addr;
        addr = ether->src_addr;
        ether->src_addr = ether->dst_addr;
        ether->dst_addr = addr;

        ret = write(tap, buf, len);
        printf("Write Bytes %ld\n", ret);
    }

    return 0;
}

发包工具

https://files.cnblogs.com/files/correct/NetAssist.zip

posted @   correct  阅读(285)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示
目录