diff options
| author | lijia <[email protected]> | 2020-03-18 22:01:54 +0800 |
|---|---|---|
| committer | lijia <[email protected]> | 2020-03-18 22:01:54 +0800 |
| commit | 2e6da7600c366f3ff36d4d4db3cabcd245b5c3ec (patch) | |
| tree | 10d5be75c061ccf41626d103a092141e2438b3fa | |
| parent | 1d23241d7bb60cb443a521c2ed5281190d3f096e (diff) | |
1.packet_io_tun模式增加static NAT, 修改ip使kni, tfe收到的数据包与外部原始包不同,避免协议栈冲突;
2.更新tun_transparent初始化脚本;
3.修复packet_io_tun模式的tcpdump_mesa捕包流程.
| -rw-r--r-- | src/packet_io/cycle_pkt_dump_through_write_offset.c | 8 | ||||
| -rw-r--r-- | src/packet_io/packet_io_tun.c | 88 | ||||
| -rw-r--r-- | src/packet_io/sendpacket.c | 5 | ||||
| -rw-r--r-- | test/Makefile | 1 | ||||
| -rw-r--r-- | test/test_app_sapp.c | 67 | ||||
| -rw-r--r-- | tools/tun_transparent/Makefile | 13 | ||||
| -rw-r--r-- | tools/tun_transparent/Makefile.user | 38 | ||||
| -rw-r--r-- | tools/tun_transparent/bridge_r2 | 5 | ||||
| -rw-r--r-- | tools/tun_transparent/bridge_r3 | 17 | ||||
| -rw-r--r-- | tools/tun_transparent/sapp_tun_bridge_kmodule.c | 396 | ||||
| -rw-r--r-- | tools/tun_transparent/sapp_tun_bridge_user.c (renamed from test/eth_tun_bridge.c) | 341 | ||||
| -rw-r--r-- | tools/tun_transparent/start_tun_env.sh (renamed from tools/tun_transparent_script/start_tun_env.sh) | 91 | ||||
| -rw-r--r-- | tools/tun_transparent/stop_tun_env.sh | 9 | ||||
| -rw-r--r-- | tools/tun_transparent/tun_ip_convert.c | 41 | ||||
| -rw-r--r-- | tools/tun_transparent_script/stop_tun_env.sh | 25 |
15 files changed, 1052 insertions, 93 deletions
diff --git a/src/packet_io/cycle_pkt_dump_through_write_offset.c b/src/packet_io/cycle_pkt_dump_through_write_offset.c index acd8eec..b3975be 100644 --- a/src/packet_io/cycle_pkt_dump_through_write_offset.c +++ b/src/packet_io/cycle_pkt_dump_through_write_offset.c @@ -489,16 +489,16 @@ static void __do_cycle_pkt_dump_udp_socket(int thread_seq, const raw_pkt_t *p_ra /* bingo, match filter, sendto */ ret = sendto(pkt_dump_udp_pkt_sd[thread_seq], - (char *)p_raw_pkt->raw_pkt_data, /* ����ʱʹ���ڲ����ݰ�ͷ, ��Ҫ��������ԭʼ�� */ - p_raw_pkt->raw_pkt_len, /* ����ʱʹ���ڲ����ݰ�ͷ, ��Ҫ��������ԭʼ�� */ + pktdata,//(char *)p_raw_pkt->raw_pkt_data, /* ����ʱʹ���ڲ����ݰ�ͷ, ��Ҫ��������ԭʼ�� */ + pktlen,//p_raw_pkt->raw_pkt_len, /* ����ʱʹ���ڲ����ݰ�ͷ, ��Ҫ��������ԭʼ�� */ MSG_DONTWAIT, (const struct sockaddr *)&udp_recv_addr, sizeof(udp_recv_addr)); if((ret < 0) && (EINTR == errno)){ /* ���ȱ�֤sapp��������, ���ж���ɵķ���ʧ��ֻ����һ��, ������������ */ ret = sendto(pkt_dump_udp_pkt_sd[thread_seq], - (char *)p_raw_pkt->raw_pkt_data, - p_raw_pkt->raw_pkt_len, + pktdata,///(char *)p_raw_pkt->raw_pkt_data, + pktlen,///p_raw_pkt->raw_pkt_len, MSG_DONTWAIT, (const struct sockaddr *)&udp_recv_addr, sizeof(udp_recv_addr)); diff --git a/src/packet_io/packet_io_tun.c b/src/packet_io/packet_io_tun.c index bd6f0e6..69259fb 100644 --- a/src/packet_io/packet_io_tun.c +++ b/src/packet_io/packet_io_tun.c @@ -21,12 +21,14 @@ extern "C" { #include <pcap.h> +#define TUN_MODE_NAT_XOR_IP (0xFFFFFFFF) + static char *tun_up_dev_name; static char *tun_down_dev_name; static int g_tun_fd[2]; /* DIR_ROUTE_UP */ static PACKET_IO_CB_T g_tun_work_fun; static int g_tun_topology_mode = NET_CONN_SERIAL_2CARD; -static int g_tun_version = 20200220; +static int g_tun_version = 20200317; static MESA_lqueue_head g_tun_work_queue; @@ -36,12 +38,36 @@ typedef struct{ }tun_send_handle; -/* 为了一次性把数据全部copy到queue里, 使用连续内存结构 */ +/* 为了一次性把数据全部copy到queue�? 使用连续内存结构 */ typedef struct{ raw_pkt_t raw_pkt; char pkt_buf[SENDPACKET_BUF_LEN]; }tun_raw_pkt_t; +static void tun_xor_static_nat(struct mesa_ip4_hdr *ihdr) +{ + struct mesa_udp_hdr *udp_header; + struct mesa_tcp_hdr *tcp_header; + int payload_len; + + ihdr->ip_src.s_addr ^= TUN_MODE_NAT_XOR_IP; + ihdr->ip_dst.s_addr ^= TUN_MODE_NAT_XOR_IP; + + payload_len = ntohs(ihdr->ip_len) - ihdr->ip_hl * 4; + + sendpacket_do_checksum((unsigned char *)ihdr, IPPROTO_IP, sizeof(struct ip)); + if(IPPROTO_TCP == ihdr->ip_p){ + tcp_header = (struct mesa_tcp_hdr *)((char *)ihdr + ihdr->ip_hl * 4); + tcp_header->th_sum = 0; + sendpacket_do_checksum((unsigned char *)ihdr, IPPROTO_TCP, payload_len); + }else if(IPPROTO_UDP == ihdr->ip_p){ + udp_header = (struct mesa_udp_hdr *)((char *)ihdr + ihdr->ip_hl * 4); + udp_header->uh_sum = 0; + sendpacket_do_checksum((unsigned char *)ihdr, IPPROTO_UDP, payload_len); + } +} + + int tun_dl_io_set_topology_mode(int topology_mode) { return 0; @@ -142,7 +168,11 @@ int tun_dl_io_low_level_send(void *phandle, UINT8 *data,int datalen, int dir_reverse, ret; send_again: - /* 发包时, dir要取反一次, 因为从tun0收的包,rcv_dir=0, 如果send_dir=0, 即同向发送,实际是从tun1发走 */ + /* 发包时, dir要取反一次, 因为从tun0收的包,rcv_dir=0, 如果send_dir=0, 即业务插件要同向发送,实际是从tun1发走 */ + + /* 发包之前恢复原始ip地址, kni, tfe看到的都是假象 */ + tun_xor_static_nat((struct mesa_ip4_hdr *)data); + ret = write(g_tun_fd[(dir & 0x1) ^ 1], data, datalen); if(ret < 0){ if((EAGAIN == errno) || (EINTR == errno) ){ @@ -183,7 +213,7 @@ static int ifconfig_device_up(const char *interface_name) } //指定网卡名称且up sprintf(ifr.ifr_name, "%s", interface_name); - /* 获得接口的标志 */ + /* 获得接口的标�?*/ if ((err = ioctl(socket_fd, SIOCGIFFLAGS, (void *)&ifr)) < 0) { perror("ioctl SIOCGIFADDR"); close(socket_fd); @@ -241,8 +271,7 @@ int tun_alloc(char *dev, int flags) return err; } - // 一旦设备开启成功,系统会给设备分配一个名称,对于tun设备,一般为tunX,X为从0开始的编号; - // 对于tap设备,一般为tapX + // 一旦设备开启成功,系统会给设备分配一个名称,对于tun设备,一般为tunX,X为从0开始的编号�? // 对于tap设备,一般为tapX strcpy(dev, ifr.ifr_name); return fd; @@ -289,17 +318,40 @@ void *tun_work_thread(void *arg) int sapp_ret, queue_ret; tun_raw_pkt_t tun_raw_pkt; long buf_len; + struct mesa_ip4_hdr *ihdr; + struct mesa_ethernet_hdr *ehdr; + int total_call_times = 0; + int polling_work_times = 0; while(1){ buf_len = sizeof(tun_raw_pkt); - queue_ret = MESA_lqueue_get_head(g_tun_work_queue, &tun_raw_pkt, &buf_len); + queue_ret = MESA_lqueue_try_get_head(g_tun_work_queue, &tun_raw_pkt, &buf_len); if(queue_ret >= 0){ tun_raw_pkt.raw_pkt.__lib_raw_pkt_data = tun_raw_pkt.pkt_buf; - tun_raw_pkt.raw_pkt.raw_pkt_data = tun_raw_pkt.pkt_buf; + tun_raw_pkt.raw_pkt.raw_pkt_data = tun_raw_pkt.pkt_buf + 14; + + ehdr = (struct mesa_ethernet_hdr *)tun_raw_pkt.pkt_buf; + ehdr->ether_type = htons(ETH_P_IP); + + ihdr = (struct mesa_ip4_hdr *)tun_raw_pkt.raw_pkt.raw_pkt_data; + /* 调用插件之前先伪造ip地址, 欺骗kni, tfe和tfe-kmod模块 */ + tun_xor_static_nat(ihdr); sapp_ret = g_tun_work_fun(&tun_raw_pkt.raw_pkt, tun_raw_pkt.raw_pkt.route_dir, 0); if((g_tun_topology_mode & __NET_CONN_SERIAL) && (PASS == sapp_ret)){ - tun_forward_pkt(0, tun_raw_pkt.pkt_buf, tun_raw_pkt.raw_pkt.raw_pkt_len, tun_raw_pkt.raw_pkt.route_dir); + /* 转发之前恢复原始ip地址 */ + tun_xor_static_nat(ihdr); + tun_forward_pkt(0, tun_raw_pkt.raw_pkt.raw_pkt_data, tun_raw_pkt.raw_pkt.raw_pkt_len, tun_raw_pkt.raw_pkt.route_dir); + } + }else{ + if(stream_process_polling(0) != 0){ + polling_work_times++; + } + total_call_times++; + + if(total_call_times >= 100){ + total_call_times = 0; + usleep(1); } } } @@ -310,7 +362,7 @@ void *tun_work_thread(void *arg) void *tun_rcv_thread(void *arg) { - int rn0, queue_ret; + int rcv_byte, queue_ret; tun_raw_pkt_t tun_raw_pkt; long route_dir_arg = (long)arg; unsigned char route_dir = (unsigned char)route_dir_arg; @@ -327,12 +379,18 @@ void *tun_rcv_thread(void *arg) tun_raw_pkt.raw_pkt.route_dir = route_dir; while(1){ - rn0 = read(g_tun_fd[route_dir], tun_raw_pkt.pkt_buf, sizeof(tun_raw_pkt.pkt_buf)); - if(rn0 > 0){ + /* 预留mac头部, 方便tcpdump_mesa捕包分析 */ + rcv_byte = read(g_tun_fd[route_dir], tun_raw_pkt.pkt_buf+14, sizeof(tun_raw_pkt.pkt_buf)-14); + if(rcv_byte > 0){ + if(0x60 == (tun_raw_pkt.pkt_buf[14] & 0xF0)){ + /* TODO: tun模式先不支持ipv6 */ + continue; + } + //tun_raw_pkt.raw_pkt.__lib_raw_pkt_data = pkt; //tun_raw_pkt.raw_pkt.raw_pkt_data = pkt; - tun_raw_pkt.raw_pkt.__lib_raw_pkt_len = rn0; - tun_raw_pkt.raw_pkt.raw_pkt_len = rn0; + tun_raw_pkt.raw_pkt.__lib_raw_pkt_len = rcv_byte; + tun_raw_pkt.raw_pkt.raw_pkt_len = rcv_byte; tun_raw_pkt.raw_pkt.route_dir = route_dir; queue_ret = MESA_lqueue_join_tail(g_tun_work_queue, &tun_raw_pkt, sizeof(tun_raw_pkt)); if(queue_ret < 0){ @@ -372,7 +430,7 @@ void tun_dl_io_run(void) pthread_create(&pid, NULL, tun_work_thread, NULL); - /* tun模式暂时只支持1个线程, 非阻塞模式分别处理两个tun虚拟网卡 */ + /* tun模式暂时只支�?个线�? 非阻塞模式分别处理两个tun虚拟网卡 */ pthread_create(&pid, NULL, tun_rcv_thread, (void *)DIR_ROUTE_UP); pthread_create(&pid, NULL, tun_rcv_thread, (void *)DIR_ROUTE_DOWN); diff --git a/src/packet_io/sendpacket.c b/src/packet_io/sendpacket.c index 2f78994..3166d94 100644 --- a/src/packet_io/sendpacket.c +++ b/src/packet_io/sendpacket.c @@ -2993,6 +2993,11 @@ int __sapp_inject_pkt(struct streaminfo *raw_stream, enum sapp_inject_opt sio, /* ������ǰ�� */ inject_stream = raw_stream->pfather; inject_stream_pr = (struct streaminfo_private *)inject_stream; + }else{ + if((ADDR_TYPE_IPV4 == inject_stream->addr.addrtype) + || (ADDR_TYPE_TCP == inject_stream->addr.addrtype)){ + set_build_layer_tcp_args(thread_num, TH_PUSH|TH_ACK, MESA_rand_range(1000, 1460), 0); + } } raw_stream_pr = (struct streaminfo_private *)raw_stream; diff --git a/test/Makefile b/test/Makefile index 5f8b757..712c7ac 100644 --- a/test/Makefile +++ b/test/Makefile @@ -53,6 +53,7 @@ wangyan_gdev_measurement.so:wangyan_gdev_measurement.c $(CC) -o $@ -shared -fPIC $(INCS) $(CFLAGS) -DIOMODE_MARSIO=1 $^ $(MODULES) cp $@ ../bin/plug/business/wangyan_gdev_measurement/$@ + sapp_so_run:test_sapp_so.o $(CC) -o $@ -g $(INCS) $(CFLAGS) $^ -lpcap -ldl cp $@ ../bin; diff --git a/test/test_app_sapp.c b/test/test_app_sapp.c index f7a134b..90e69d5 100644 --- a/test/test_app_sapp.c +++ b/test/test_app_sapp.c @@ -1400,10 +1400,68 @@ char test_sendfake_udp_pkt(struct streaminfo *stream,void **pme, int thread_seq, } +static void test_inject_tcp_pkt_with_this_hdr(struct streaminfo *stream,void **pme, int thread_seq,const void *raw_pkt) +{ + char fake_http_data[] = "HTTP/1.1 200 OK\r\nServer: Apache-Coyote/1.1\r\nContent-Type: text/html;charset=UTF-8\r\nContent-Language: zh-CN\r\nContent-Length: 32\r\nConnection: Close\r\n\r\n<html><head>HaHaHa</head></html>"; + + char pkt_header_payload[2048]; + struct mesa_ip4_hdr *send_ihdr; + struct mesa_tcp_hdr *send_thdr; + + const struct mesa_ip4_hdr *raw_ihdr; + const struct mesa_tcp_hdr *raw_thdr; + int raw_tcp_payload_len; + int send_pkt_len; + + raw_ihdr = (struct mesa_ip4_hdr *)raw_pkt; + raw_thdr = (struct mesa_tcp_hdr *)((char *)raw_ihdr + raw_ihdr->ip_hl*4); + raw_tcp_payload_len = ntohs(raw_ihdr->ip_len) - raw_ihdr->ip_hl*4 - raw_thdr->th_off * 4; + + /* 当前包是C2S方向的GET, 需要回复一个虚假的S2C方向的RESPONSE */ + send_ihdr = pkt_header_payload; + send_thdr = (struct mesa_tcp_hdr *)((char *)send_ihdr + sizeof(struct mesa_ip4_hdr)); + + sendpacket_build_tcp(ntohs(raw_thdr->th_dport), + ntohs(raw_thdr->th_sport), + ntohl(raw_thdr->th_ack), + ntohl(raw_thdr->th_seq)+raw_tcp_payload_len, + 0x18, + 100, + 0, + NULL, + 0, + (unsigned char *)send_thdr); + + sendpacket_build_ipv4(sizeof(struct mesa_tcp_hdr) + sizeof(fake_http_data), + 0, + 0x1111, + IP_DF, + 100, + IPPROTO_TCP, + raw_ihdr->ip_dst.s_addr, + raw_ihdr->ip_src.s_addr, + NULL, + 0, + (unsigned char *)send_ihdr); + memcpy(pkt_header_payload + sizeof(struct mesa_ip4_hdr) + sizeof(struct mesa_tcp_hdr), + fake_http_data, + sizeof(fake_http_data)); + + sendpacket_do_checksum(send_ihdr, IPPROTO_IP, sizeof(struct mesa_ip4_hdr)); + sendpacket_do_checksum(send_ihdr, IPPROTO_TCP, sizeof(struct mesa_tcp_hdr) + sizeof(fake_http_data)); + + send_pkt_len = sizeof(struct mesa_ip4_hdr) + sizeof(struct mesa_tcp_hdr) + sizeof(fake_http_data); + + sapp_inject_pkt(stream, SIO_EXCLUDE_THIS_LAYER_HDR, pkt_header_payload, send_pkt_len, stream->routedir ^ 1); + + return; +} + char test_inject_tcp_pkt(struct streaminfo *stream,void **pme, int thread_seq,const void *raw_pkt) { - char fake_http_data[] = "HTTP/1.1 200 OK\r\nServer: Apache-Coyote/1.1\r\nContent-Type: text/html;charset=UTF-8\r\nContent-Language: zh-CN\r\nContent-Length: 32\r\nDate: Tue, 09 Sep 2014 08:21:07 GMT\r\n\r\n<html><head>HaHaHa</head></html>"; + char fake_http_data[] = "HTTP/1.1 200 OK\r\nServer: Apache-Coyote/1.1\r\nContent-Type: text/html;charset=UTF-8\r\nContent-Language: zh-CN\r\nContent-Length: 32\r\nConnection: Close\r\n\r\n<html><head>HaHaHa</head></html>"; char plug_ret = APP_STATE_DROPME; + int optval; if(OP_STATE_CLOSE == stream->opstate){ return plug_ret; @@ -1413,8 +1471,13 @@ char test_inject_tcp_pkt(struct streaminfo *stream,void **pme, int thread_seq,co if((DIR_C2S == stream->curdir) && (memmem(stream->ptcpdetail->pdata, stream->ptcpdetail->datalen, "hijack", 6) != NULL)){ printf("found key 'hijack', send fake http response ' hahaha'!\n"); - MESA_inject_pkt(stream, fake_http_data, sizeof(fake_http_data), raw_pkt, stream->routedir ^ 1); + //MESA_inject_pkt(stream, fake_http_data, sizeof(fake_http_data), raw_pkt, stream->routedir ^ 1); + //sapp_inject_pkt(stream, SIO_DEFAULT, fake_http_data, sizeof(fake_http_data), stream->routedir ^ 1); + test_inject_tcp_pkt_with_this_hdr(stream, pme, thread_seq, raw_pkt); plug_ret |= APP_STATE_DROPPKT; + + optval = 1; + MESA_set_stream_opt(stream, MSO_DROP_STREAM, &optval, sizeof(int)); } } diff --git a/tools/tun_transparent/Makefile b/tools/tun_transparent/Makefile new file mode 100644 index 0000000..a4a393b --- /dev/null +++ b/tools/tun_transparent/Makefile @@ -0,0 +1,13 @@ +obj-m := sapp_tun_bridge_kmodule.o + +modules-objs:= sapp_tun_bridge_kmodule.o + +KDIR := /lib/modules/`uname -r`/build + +PWD := $(shell pwd) + +default: + make -C $(KDIR) M=$(PWD) modules + +clean: + rm -rf *.o *.ko *.mod.c .tmp_versions
\ No newline at end of file diff --git a/tools/tun_transparent/Makefile.user b/tools/tun_transparent/Makefile.user new file mode 100644 index 0000000..b8cf9d1 --- /dev/null +++ b/tools/tun_transparent/Makefile.user @@ -0,0 +1,38 @@ +CC = gcc +CCC = g++ +CFLAGS = -g -fPIC +CFLAGS += -D__USE_BSD=1 -D__FAVOR_BSD=1 -D__USE_MISC=1 -D_GNU_SOURCE=1 +CFLAGS += $(OPTFLAGS) +OBJECTS = test_app_sapp.o trace_delay.o terminal_tag.o g_device_plug.o +MODULES = + +BIN_PATH = ../bin/ + +TARGET = sapp_tun_bridge_user + +INCS = +INCS += -I ../include +INCS += -I../include/private +INCS += -I../include/public +INCS += -I../include/public/stream_inc/ +INCS += -I../include/support/ +INCS += -I/opt/MESA/include +INCS += -I/opt/MESA/include/MESA + + +.PHONY: all +all: $(TARGET) + + +sapp_tun_bridge_user:sapp_tun_bridge_user.c + gcc -o $@ $^ -g -O0 $(CFLAGS) -lpthread -lpcap -lnetfilter_queue -lnfnetlink + +.c.o: + $(CC) -c -o $@ $(CFLAGS) -I. $(INCS) $< + +.cpp.o: + $(CCC) -c -o $@ $(CFLAGS) -I. $(INCS) $< + +clean: + rm -f $(TARGET) $(OBJECTS) + diff --git a/tools/tun_transparent/bridge_r2 b/tools/tun_transparent/bridge_r2 new file mode 100644 index 0000000..22eb356 --- /dev/null +++ b/tools/tun_transparent/bridge_r2 @@ -0,0 +1,5 @@ +#!/bin/sh + +killall -9 bridge_r3 sapp_tun_bridge_user +./bridge_r3 $@ &> /dev/null & + diff --git a/tools/tun_transparent/bridge_r3 b/tools/tun_transparent/bridge_r3 new file mode 100644 index 0000000..d6993fd --- /dev/null +++ b/tools/tun_transparent/bridge_r3 @@ -0,0 +1,17 @@ +#!/bin/sh + +while [ 1 ]; do + count=`ls -l core.* |wc -l` + echo $count + if [ $count -lt 5 ] + then + echo "set unlimited" + ulimit -c unlimited + else + ulimit -c 0 + fi + + ./sapp_tun_bridge_user $@ > /dev/null + echo sapp_tun_bridge_user crashed, restart at `date +"%w %Y/%m/%d, %H:%M:%S"` >> RESTART.log + sleep 1 +done diff --git a/tools/tun_transparent/sapp_tun_bridge_kmodule.c b/tools/tun_transparent/sapp_tun_bridge_kmodule.c new file mode 100644 index 0000000..8a11c0d --- /dev/null +++ b/tools/tun_transparent/sapp_tun_bridge_kmodule.c @@ -0,0 +1,396 @@ +#include <linux/inet.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/netfilter.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/netfilter_ipv4.h> +#include <linux/skbuff.h> +#include <linux/udp.h> +#include <linux/tcp.h> +#include <net/ip.h> +#include <net/udp.h> +#include <net/tcp.h> + +#include <linux/ip.h> +#include <linux/version.h> + +#if 0 + #define dprint(fmt, args...) printk (KERN_INFO fmt, ## args) +#else + #define dprint(fmt, args...) +#endif + +static char *devname = "xxx"; +static char *devip = "169.254.1.1"; +static char *devmac = "FF:FF:FF:FF:FF:FF"; + +static unsigned int local_dev_ip_bin; /* network order */ +static unsigned char local_dev_mac_bin[ETH_ALEN]; + +module_param(devname, charp,S_IRUGO); +module_param(devip, charp,S_IRUGO); +module_param(devmac,charp,S_IRUGO); + + +static char nf_ascii_to_hex(char ascii) +{ + char c = 0; + + switch(ascii) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + c = ascii - 0x30; + break; + + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + c = 10 + ascii - 0x61; + break; + + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + c = 10 + ascii - 0x41; + break; + } + + return c; +} + + +/* 2012-04-11 LiJia add,将MAC字符串形式转换为16进制MAC地址. +参数: + str: MAC地址字符串 + delim: 字符串分隔符,常见为':', '-'等,如: xx:xx:xx:xx:xx:xx + 如果字符串无分隔符,delim设为-1. + mac: 存储MAC地址的数组(指针),结果为网络序, + 如网卡MAC地址为11:22:33:44:55:66,则mac[0]为0x11,mac[5]为0x66. +返回值: + 0: 正常 + -1:错误 +*/ +static int nf_mac_pton(const char *str, int delim, char *mac) +{ +#define MAC_STR_LEN_DELIM (17) /* length of "11:22:33:44:55:66" */ +#define MAC_STR_LEN_NODELIM (12) /* length of "112233445566" */ + const char *s = str; + int i; + + /* 检查输入合法性 */ + if(delim != -1) + { + if(strlen(str) != MAC_STR_LEN_DELIM) + { + return -1; + } + } + else + { + if(strlen(str) != MAC_STR_LEN_NODELIM) + { + return -1; + } + } + + /* 检查输入合法性,同时转换成16进制值 */ + for(i = 0; i < 6; i++) + { + mac[i] = 0; /* 先清零,赋值语句都是或操作 */ + if(isxdigit(*s)==0) + { + return -1; + } + mac[i] |= nf_ascii_to_hex(*s) << 4; + s++; + + if(isxdigit(*s)==0) + { + return -1; + } + mac[i] |= nf_ascii_to_hex(*s); + s++; + + if((delim != -1) && i<5 && (*s++ != (char)delim)) + { + return -1; + } + } + + return 0; +} + +/* + 从网关收到的回复包, dip肯定是本机物理网卡的ip, + 要把dip改成iptables的SNAT目标ip, 169.254.254.254, + 第1, 欺骗内核, 让此包的四元组跟本机无关, 协议栈不做特殊处理; + 第2, iptables的SNAT才能进一步恢复NAT之前, ppp0设备的ip. +*/ +static void modify_dip_spoofing_kernal(struct sk_buff *skb) +{ + struct iphdr *ip_header; + struct udphdr *udp_header; + struct tcphdr *tcp_header; + int payload_len; + + ip_header = (struct iphdr *) skb_network_header (skb); + + dprint("rcv pkt from %s, modify dip to '169.254.254.254'\n", skb->dev->name); + ip_header->daddr = 0xFEFEFEA9;//169.254.254.254 + ip_send_check(ip_header); + + if(IPPROTO_UDP == ip_header->protocol){ + udp_header = (struct udphdr *)((char *)ip_header + ip_header->ihl * 4); + udp_header->check = 0; + udp_lib_checksum_complete(skb); + }else if(IPPROTO_TCP == ip_header->protocol){ + tcp_header = (struct tcphdr *)((char *)ip_header + ip_header->ihl * 4); + payload_len = ntohs(ip_header->tot_len) - ip_header->ihl * 4; + tcp_header->check = 0; + + //TODO, 下面方式的tcp校验和计算不对!! + //tcp_checksum_complete(skb); + tcp_header->check = tcp_v4_check(payload_len, ip_header->saddr, ip_header->daddr, + csum_partial((char *)tcp_header, payload_len, 0)); + } +} + +/* + 处理从物理网卡收到的流量, + 只有dmac, dip都是本机的, 才可能是sapp串联流量. +*/ +static unsigned int phy_dev_decide(struct sk_buff *skb, const char *devname) +{ + struct ethhdr *ehdr; + //struct udphdr *udp_header; + struct tcphdr *tcp_header; + struct iphdr *ip_header; + unsigned int action = NF_ACCEPT; + + ehdr = (struct ethhdr *)skb_mac_header(skb); + + /* DMAC不是给本机的包, 可能是广播、组播等包, 给内核处理 */ + if(memcmp(ehdr->h_dest, local_dev_mac_bin, ETH_ALEN) != 0){ + dprint("recv pkt from %s, dst mac is not local, action=%d\n", skb->dev->name, action); + return NF_ACCEPT; + } + + if(ntohs(ehdr->h_proto) != ETH_P_IP){ + /* 非ip包, 给内核协议栈处理 */ + dprint("recv pkt from %s, is not ipv4, action=%d\n", skb->dev->name, action); + return NF_ACCEPT; + } + +#if 0//debug + printk("smac:%02x-%02x-%02x-%02x-%02x-%02x, dmac:%02x-%02x-%02x-%02x-%02x-%02x\n", + ehdr->h_source[0], + ehdr->h_source[1], + ehdr->h_source[2], + ehdr->h_source[3], + ehdr->h_source[4], + ehdr->h_source[5], + + ehdr->h_dest[0], + ehdr->h_dest[1], + ehdr->h_dest[2], + ehdr->h_dest[3], + ehdr->h_dest[4], + ehdr->h_dest[5] + ); +#endif + + ip_header = (struct iphdr *) skb_network_header (skb); + /* DIP不是给本机的包, 给内核处理 */ + if(ip_header->daddr != local_dev_ip_bin){ + //printk (KERN_INFO "### recv not local dip packet, 0x%x!.\n", ntohl(ip_header->daddr)); + return NF_ACCEPT; + } + + switch(ip_header->protocol){ + /* UDP, ICMP等包不太好区分哪个包是本机所发出的, 默认给sapp, */ + case IPPROTO_UDP: + //dprint("sapp-kmod: rcv udp pkt from %s, to user queue.\n", devname); + modify_dip_spoofing_kernal(skb); + action = NF_QUEUE; + break; + + case IPPROTO_ICMP: + dprint("sapp-kmod: rcv icmp pkt from %s, to user queue.\n", devname); + modify_dip_spoofing_kernal(skb); + action = NF_QUEUE; + break; + + case IPPROTO_ESP: + //dprint("sapp-kmod: rcv ip-esp pkt from %s, to user queue.\n", devname); + modify_dip_spoofing_kernal(skb); + action = NF_QUEUE; + break; + + case IPPROTO_TCP: + { + /* 只保证物理机的ssh, pptp vpn的连通性, 其他都给sapp */ + tcp_header = (struct tcphdr *)( (char *)ip_header + ip_header->ihl * 4); + if((ntohs(tcp_header->dest) == 22) + ||(ntohs(tcp_header->dest) == 1723)){ + //dprint("sapp-kmod: rcv tcp and (port 22 or port 1723) pkt, to kernel ip stack."); + action = NF_ACCEPT; + }else{ + dprint("sapp-kmod: rcv tcp and not port 22 and not port 1723 pkt, to user queue.\n"); + modify_dip_spoofing_kernal(skb); + action = NF_QUEUE; + } + } + break; + + case IPPROTO_GRE: /* pptp vpn流量给sapp */ + //dprint("sapp-kmod: rcv gre pkt from %s, to kernel ip stack\n", devname); + action = NF_ACCEPT; + break; + + default: + break; + } + + return action; +} + +static unsigned int virtual_dev_decide(struct sk_buff *skb, const char *devname) +{ + return NF_ACCEPT; /* from all virtual device action is accept */ + + if(strncasecmp(devname, "tun_kni", strlen("tun_kni")) == 0){ + //dprint("sapp-kmod: recv from dev:%s, accept it\n", devname); + return NF_ACCEPT; /* kni with tfe */ + } + + if(strncasecmp(devname, "lo", strlen("lo")) == 0){ + return NF_ACCEPT; /* loopback */ + } + + if(strncasecmp(devname, "ppp", 3) == 0){ + return NF_ACCEPT; /* ppp0, ppp1, ppp2, pptp vpn vdev */ + } + + /* tun0 tun1是sapp串联的两块虚拟卡, 要使用STOP机制, + 即不让后续的hook再处理, 跳过tfe模块, 只给系统内核. + */ + if(strncasecmp(devname, "tun0", strlen("tun0")) == 0){ + //dprint("sapp-kmod: recv from dev:%s, stop it\n", devname); + return NF_ACCEPT; /* stop follow hooks and to sapp user space */ + } + + if(strncasecmp(devname, "tun1", strlen("tun1")) == 0){ + //dprint("sapp-kmod: recv from dev:%s, stop it\n", devname); + return NF_ACCEPT; /* stop follow hooks and to sapp user space */ + } + + return NF_ACCEPT; /* default is accept */ +} + +/* This function to be called by hook. */ +static unsigned int hook_func (unsigned int hooknum, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, int (*okfn) (struct sk_buff *)) +{ + unsigned int action = NF_ACCEPT; + + if(strncasecmp(skb->dev->name, devname, strlen(devname)) == 0){ + action = phy_dev_decide(skb, skb->dev->name); + }else{ + action = virtual_dev_decide(skb, skb->dev->name); + } + + dprint("recv pkt from %s, action=%d\n", skb->dev->name, action); + + return action; +} + + +static struct nf_hook_ops stb_hook = { + .hook = hook_func, + .hooknum = NF_INET_PRE_ROUTING, /* NF_IP_LOCAL_IN */ + .pf = PF_INET, + .priority = NF_IP_PRI_FIRST, +}; + +static int __init init_nf (void) +{ + if(strncasecmp(devip, "169.254.1.1", strlen("169.254.1.1")) == 0){ + printk (KERN_ERR "sapp_tun_bridge init error, must set devip!\n"); + printk (KERN_ERR "Usage: insmod sapp_tun_bridge.ko devname=\"eth0\" devip=\"x.x.x.x\" devmac=\"xx:xx:xx:xx:xx:xx\"!\n"); + return -1; + } + if(strncasecmp(devmac, "FF:FF:FF:FF:FF:FF", strlen("FF:FF:FF:FF:FF:FF")) == 0){ + printk (KERN_ERR "sapp_tun_bridge init error, must set devmac!\n"); + printk (KERN_ERR "Usage: insmod sapp_tun_bridge.ko devname=\"eth0\" devip=\"x.x.x.x\" devmac=\"xx:xx:xx:xx:xx:xx\"!\n"); + return -1; + } + + if(strncasecmp(devname, "xxx", strlen("xxx")) == 0){ + printk (KERN_ERR "sapp_tun_bridge init error, must set devname!\n"); + printk (KERN_ERR "Usage: insmod sapp_tun_bridge.ko devname=\"eth0\" devip=\"x.x.x.x\" devmac=\"xx:xx:xx:xx:xx:xx\"!\n"); + return -1; + } + + if(nf_mac_pton(devmac, ':', local_dev_mac_bin) < 0){ + printk (KERN_ERR "sapp_tun_bridge init error, invalid devmac:%s!\n", devmac); + printk (KERN_ERR "Usage: insmod sapp_tun_bridge.ko devip=\"x.x.x.x\" devmac=\"xx:xx:xx:xx:xx:xx\"!\n"); + return -1; + } + + if(in4_pton(devip, strlen(devip), (unsigned char *)&local_dev_ip_bin, -1, NULL) < 0){ + printk (KERN_ERR "sapp_tun_bridge init error, invalid devip:%s!\n", devip); + printk (KERN_ERR "Usage: insmod sapp_tun_bridge.ko devip=\"x.x.x.x\" devmac=\"xx:xx:xx:xx:xx:xx\"!\n"); + return -1; + } + + printk (KERN_INFO "Register sapp_tun_bridge module succ, local devip:%s, devmac:%02x-%02x-%02x-%02x-%02x-%02x\n", + devip, + local_dev_mac_bin[0], + local_dev_mac_bin[1], + local_dev_mac_bin[2], + local_dev_mac_bin[3], + local_dev_mac_bin[4], + local_dev_mac_bin[5] + ); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0) + nf_register_net_hook (&init_net, &stb_hook); +#else + nf_register_hook (&stb_hook); +#endif + + return 0; +} + +static void __exit exit_nf (void) +{ + printk (KERN_INFO "Unregister sapp_tun_bridge module.\n"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0) + nf_unregister_net_hook (&init_net, &stb_hook); +#else + nf_unregister_hook (&stb_hook); +#endif +} + +module_init (init_nf); +module_exit (exit_nf); +MODULE_LICENSE ("GPL"); + diff --git a/test/eth_tun_bridge.c b/tools/tun_transparent/sapp_tun_bridge_user.c index bc05cfc..438dad7 100644 --- a/test/eth_tun_bridge.c +++ b/tools/tun_transparent/sapp_tun_bridge_user.c @@ -13,12 +13,26 @@ #include <linux/if_tun.h> #include <assert.h> #include <netinet/ip.h> +#include <netinet/ip6.h> + +#include <netinet/tcp.h> +#include <netinet/udp.h> + #include <ctype.h> #include <arpa/inet.h> #include <pthread.h> -//#include <net/if.h> -//#include <netpacket/packet.h> +#include <linux/netfilter.h> /* for NF_ACCEPT */ +#include <libnetfilter_queue/libnetfilter_queue.h> + + +#if 1 + #define dprint(fmt, args...) printf(fmt, ## args) +#else + #define dprint(fmt, args...) +#endif +#define SAPP_BRIDGE_SNAT_ENABLE (0) +#define SAPP_BRIDGE_SNAT_SIP (0xFEFEFEA9) //169.254.254.254 /* 此程序可以跑通单机单网卡模式下的串联功能, @@ -27,6 +41,13 @@ #define USE_TUN_MODE (1) /* 虚拟设备用tun还是TAP, 1:tun; 0:tap */ +/* + * Checksum stuff + */ +#define BRIDGE_CKSUM_CARRY(x) \ + (x = (x >> 16) + (x & 0xffff), (~(x + (x >> 16)) & 0xffff)) + + static pcap_t * tun_pcap_handle; static pcap_t * phy_pcap_handle; @@ -36,6 +57,9 @@ static char *tun_dev_name; static struct sockaddr tun_sock_addr; static struct sockaddr phy_sock_addr; +static struct nfq_handle *g_nfq_handle; +static int g_nfq_fd; + static int phy_dev_fd, tun_dev_fd; static unsigned int local_phy_dev_ip_net; @@ -238,46 +262,295 @@ static inline int is_private_addr_v4(unsigned int ip_add_host) return 0; } +static int bridge_in_cksum(u_int16_t *addr, int len) +{ + int sum; + int nleft; + u_int16_t ans; + u_int16_t *w; + + sum = 0; + ans = 0; + nleft = len; + w = addr; + + while (nleft > 1) + { + sum += *w++; + nleft -= 2; + } + if (nleft == 1) + { + *(char *)(&ans) = *(char *)w; + sum += ans; + } + return (sum); +} + -void phy_pkt_cb(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet) +static int bridge_do_checksum(unsigned char *buf, int protocol, int len) +{ + struct ip *iph_p; + struct ip6_hdr *ip6h_p; + int ip_hl; + int sum; + int is_ipv6 = 0; + + sum = 0; + iph_p = (struct ip *)buf; + + if(4 == iph_p->ip_v) /* IP版本号字段,IPv4和IPv6格式是相同的 */ + { + ip_hl = iph_p->ip_hl << 2; + ip6h_p = NULL; + } + else if(6 == iph_p->ip_v) + { + ip6h_p = (struct ip6_hdr *)buf; + iph_p = NULL; + ip_hl = sizeof(struct ip6_hdr); + is_ipv6 = 1; + } + else + { + return (-1); + } + + /* + * Dug Song came up with this very cool checksuming implementation + * eliminating the need for explicit psuedoheader use. Check it out. + */ + switch (protocol) + { + /* + * Style note: normally I don't advocate declaring variables inside + * blocks of control, but it makes good sense here. -- MDS + */ + case IPPROTO_TCP: + { + struct tcphdr *tcph_p = + (struct tcphdr *)(buf + ip_hl); + +#if (STUPID_SOLARIS_CHECKSUM_BUG) + tcph_p->th_sum = tcph_p->th_off << 2; + return (1); +#endif /* STUPID_SOLARIS_CHECKSUM_BUG */ + + tcph_p->check = 0; + /* 2012-03-19 LiJia add, for IPv6 */ + if(is_ipv6) + { + sum = bridge_in_cksum((u_int16_t *)&ip6h_p->ip6_src, 32); + } + else + { + sum = bridge_in_cksum((u_int16_t *)&iph_p->ip_src, 8); + } + sum += ntohs(IPPROTO_TCP + len); + sum += bridge_in_cksum((u_int16_t *)tcph_p, len); + tcph_p->check = BRIDGE_CKSUM_CARRY(sum); + break; + } + + case IPPROTO_UDP: + { + struct udphdr *udph_p = + (struct udphdr *)(buf + ip_hl); + + udph_p->check = 0; + /* 2012-03-19 LiJia add, for IPv6 */ + if(is_ipv6) + { + sum = bridge_in_cksum((u_int16_t *)&ip6h_p->ip6_src, 32); + } + else + { + sum = bridge_in_cksum((u_int16_t *)&iph_p->ip_src, 8); + } + sum += ntohs(IPPROTO_UDP + len); + sum += bridge_in_cksum((u_int16_t *)udph_p, len); + udph_p->check = BRIDGE_CKSUM_CARRY(sum); + break; + } + + case IPPROTO_IP: /* Dummy protocol for TCP. */ + { + iph_p->ip_sum = 0; + sum = bridge_in_cksum((u_int16_t *)iph_p, len); + iph_p->ip_sum = BRIDGE_CKSUM_CARRY(sum); + break; + } +#if 0 + + case IPPROTO_ICMP: + { + struct mesa_icmp_hdr *icmph_p = + (struct mesa_icmp_hdr *)(buf + ip_hl); + + icmph_p->icmp_sum = 0; + sum = bridge_in_cksum((u_short *)icmph_p, len); + icmph_p->icmp_sum = BRIDGE_CKSUM_CARRY(sum); + break; + } +#endif + default: + { + return (-1); + } + } + return (1); +} + + +/* pptp的控制包和数据包要返回给内核协议栈处理, 否则client拨号会失败; +*/ +static int is_need_to_kernel_pkt(const struct ip *ihdr) +{ + const struct tcphdr *thdr; + + if(IPPROTO_GRE == ihdr->ip_p){ + return 1; + } + + /* icmp优先给tun1,保证pptp vpn client的正确性, 此时物理主机的ping失效 */ + if(IPPROTO_ICMP == ihdr->ip_p){ + return 0; + } + + thdr = (const struct tcphdr *)((char *)ihdr + ihdr->ip_hl * 4); + if((22 == ntohs(thdr->dest)) + || (1723 == ntohs(thdr->dest))){ + return 1; + } + + return 0; +} + +/* + iptabels nat跟路由有冲突, 各种没调通, 先人工做一次简易应用层SNAT. +*/ +static void bridge_preout_snat(struct ip *ihdr) +{ + struct udphdr *udp_header; + struct tcphdr *tcp_header; + int payload_len; + + ihdr->ip_src.s_addr = local_phy_dev_ip_net; //sip改成本机物理网卡ip + payload_len = ntohs(ihdr->ip_len) - ihdr->ip_hl * 4; + + bridge_do_checksum((unsigned char *)ihdr, IPPROTO_IP, sizeof(struct ip)); + if(IPPROTO_TCP == ihdr->ip_p){ + tcp_header = (struct tcphdr *)((char *)ihdr + ihdr->ip_hl * 4); + tcp_header->check = 0; + bridge_do_checksum((unsigned char *)ihdr, IPPROTO_TCP, payload_len); + }else if(IPPROTO_UDP == ihdr->ip_p){ + udp_header = (struct udphdr *)((char *)ihdr + ihdr->ip_hl * 4); + udp_header->check = 0; + bridge_do_checksum((unsigned char *)ihdr, IPPROTO_UDP, payload_len); + } +} + +#if SAPP_BRIDGE_SNAT_ENABLE +/* 从物理网卡收到的包, 恢复SNAT之前的ip, 169.254.254.254 */ +static void bridge_prein_snat_recover(struct ip *ihdr) +{ + struct udphdr *udp_header; + struct tcphdr *tcp_header; + int payload_len; + + ihdr->ip_dst.s_addr = SAPP_BRIDGE_SNAT_SIP; + payload_len = ntohs(ihdr->ip_len) - ihdr->ip_hl * 4; + + bridge_do_checksum((unsigned char *)ihdr, IPPROTO_IP, sizeof(struct ip)); + if(IPPROTO_TCP == ihdr->ip_p){ + tcp_header = (struct tcphdr *)((char *)ihdr + ihdr->ip_hl * 4); + tcp_header->check = 0; + bridge_do_checksum((unsigned char *)ihdr, IPPROTO_TCP, payload_len); + }else if(IPPROTO_UDP == ihdr->ip_p){ + udp_header = (struct udphdr *)((char *)ihdr + ihdr->ip_hl * 4); + udp_header->check = 0; + bridge_do_checksum((unsigned char *)ihdr, IPPROTO_UDP, payload_len); + } +} +#endif + +static void phy_pkt_cb(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet) { int sn; - const struct ip *ihdr = (struct ip *)(packet + 14); + struct ethhdr *ehdr = (struct ethhdr *)packet; + struct ip *ihdr = (struct ip *)(packet); + struct tcphdr *thdr; //char ip_str[64]; - if((packet[12] != 0x08) || (packet[13] != 0x00)){ /* drop ipv6, arp, etc.. */ + if(ntohs(ehdr->h_proto) != ETH_P_IP){ return; } - + ihdr = (struct ip *)(packet + 14); if(local_phy_dev_ip_net != ihdr->ip_dst.s_addr){ //inet_ntop(AF_INET, &ihdr->ip_dst.s_addr, ip_str, sizeof(ip_str)); - //printf("packet from %s dst ip '%s' is not local device, ignore it!\n", phy_dev_name, ip_str); - return; - } - - if(is_private_addr_v4(ntohl(ihdr->ip_src.s_addr)) != 0){ - //inet_ntop(AF_INET, &ihdr->ip_src.s_addr, ip_str, sizeof(ip_str)); - //printf("packet from %s src ip '%s' is same submask, ignore it!\n", phy_dev_name, ip_str); + //dprint("packet from %s dst ip '%s' is not local device, ignore it!\n", phy_dev_name, ip_str); return; } + switch(ihdr->ip_p){ + /* UDP, ICMP等包不太好区分哪个包是本机所发出的, 默认给sapp, */ + case IPPROTO_UDP: + case IPPROTO_ICMP: + case IPPROTO_ESP: + break; + + case IPPROTO_TCP: + { + /* 只保证物理机的ssh, pptp vpn的连通性, 其他都给sapp */ + thdr = (struct tcphdr *)( (char *)ihdr + ihdr->ip_hl * 4); + if((ntohs(thdr->dest) == 22) + ||(ntohs(thdr->dest) == 1723)){ + return; + } + } + break; + + case IPPROTO_GRE: /* pptp vpn流量给sapp */ + return; /* 协议栈处理 */ + break; - /* 从phy捕到的包, 发给tun设备之前要剥去mac头部 */ - sn = sendto(tun_dev_fd, packet+14, pkthdr->caplen-14, 0, (struct sockaddr *)&tun_sock_addr, sizeof(struct sockaddr)); + default: + return; /* 协议栈处理 */ + break; + } + +#if SAPP_BRIDGE_SNAT_ENABLE + bridge_prein_snat_recover(ihdr); +#endif + + /* 发给tun设备 */ + sn = sendto(tun_dev_fd, ihdr, pkthdr->caplen-14, 0, (struct sockaddr *)&tun_sock_addr, sizeof(struct sockaddr)); if(sn < 0){ - printf("sendto tun error, len=%d, %s\n", pkthdr->caplen-14, strerror(errno)); + dprint("sendto tun error, len=%d, %s\n", pkthdr->caplen, strerror(errno)); + }else{ + dprint("from phy '%s' to '%s' succ, len=%d\n", phy_dev_name, tun_dev_name, pkthdr->caplen); } + return; } -void tun_pkt_cb(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet) + + +/* + tun模式下, 收到的包没有MAC, 直接是ip头部. +*/ +static void tun_pkt_cb(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet) { int sn; - unsigned char buf[2048]; + + if(0x40 != (packet[0] & 0xF0)){ + dprint("recv not ipv4 pkt from tun\n"); + return; + } #if USE_TUN_MODE - memcpy(buf+14, packet, pkthdr->caplen); /* tun模式预留mac头部空间 */ + memcpy(buf+14, packet, pkthdr->caplen); /* tun模式要预留mac头部空间 */ memcpy(buf, default_gw_mac_addr, 6); memcpy(buf+6, local_phy_mac_addr, 6); buf[12] = 0x08; @@ -290,14 +563,22 @@ void tun_pkt_cb(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * buf[13] = 0x0; #endif +#if SAPP_BRIDGE_SNAT_ENABLE + bridge_preout_snat((struct ip *)(buf + 14)); +#endif + + /* 通过raw_socket从物理网卡发出时, 必须要带mac头 */ + #if USE_TUN_MODE sn = sendto(phy_dev_fd, buf, pkthdr->caplen+14, 0, (struct sockaddr *)&phy_sock_addr, sizeof(struct sockaddr)); #else sn = sendto(phy_dev_fd, buf, pkthdr->caplen, 0, (struct sockaddr *)&phy_sock_addr, sizeof(struct sockaddr)); #endif if(sn < 0){ - printf("sendto phy error, len=%d, %s\n", pkthdr->caplen+14, strerror(errno)); - } + dprint("sendto phy error, len=%d, %s\n", pkthdr->caplen+14, strerror(errno)); + }else{ + dprint("from tun '%s' to phy '%s' succ, len=%d\n", tun_dev_name, phy_dev_name, pkthdr->caplen+14); + } } static int pcap_set_filter(pcap_t *handle, const char *filter_str) @@ -322,7 +603,7 @@ static int pcap_set_filter(pcap_t *handle, const char *filter_str) return 0; } -int pcap_init(void) +static int pcap_init(void) { char errBuf[65535]; char local_ip_str[64]; @@ -352,7 +633,6 @@ int pcap_init(void) pcap_setdirection(tun_pcap_handle, PCAP_D_IN); - return 0; } @@ -365,6 +645,7 @@ void *phy_pcap_rcv_thread(void *arg) } return NULL; + } void *tun_pcap_rcv_thread(void *arg) @@ -376,7 +657,7 @@ void *tun_pcap_rcv_thread(void *arg) return NULL; } -int sock_init(void) +static int sock_init(void) { phy_dev_fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL)); if(phy_dev_fd < 0) @@ -415,7 +696,7 @@ int sock_init(void) static void usage(void) { printf("usage: ./eth_tun_bridge <phy_device> <tun_device> <gw_mac>\n"); - printf("\t for example: ./eth_tun_bridge eth0 tun1 50:d2:f5:f3:8e:93.\n"); + printf("\t for example: ./eth_tun_bridge eth0 tun1 50:d2:f5:f3:8e:93\n"); exit(1); } @@ -424,15 +705,21 @@ int main(int argc, char *argv[]) { //int rphy, rtun; pthread_t pid; - + int i; + if(argc != 4){ + printf("args number is not 4!\n"); + for(i = 0; i < argc; i++){ + printf("%s ", argv[i]); + } + printf("\n\n"); usage(); } phy_dev_name = strdup(argv[1]); tun_dev_name = strdup(argv[2]); if(MESA_mac_pton(argv[3], ':', default_gw_mac_addr) < 0){ - printf("gw_mac is invalid!\n"); + printf("args gw_mac is invalid!\n"); usage(); } diff --git a/tools/tun_transparent_script/start_tun_env.sh b/tools/tun_transparent/start_tun_env.sh index 2a0373d..eb5ccab 100644 --- a/tools/tun_transparent_script/start_tun_env.sh +++ b/tools/tun_transparent/start_tun_env.sh @@ -1,10 +1,12 @@ #!/bin/sh -PHY_DEVICE="eth0" +PHY_DEVICE="ens33" TUN_PPP_DEVICE="tun0" TUN_INTERNET_DEVICE="tun1" -RAW_DEFAULT_GW_IP="" +RAW_DEFAULT_GW_IP="192.168.31.1" PHY_IP4_ADDR=$(ifconfig $PHY_DEVICE | grep "inet " | awk '{ print $2}') -USER_IP_NETWORK_FILE="/home/mesasoft/sapp_run/user_ip_route.ini" +USER_IP_NETWORK_FILE="./user_ip_route.ini" + +./stop_tun_env.sh set_all_user_ip_route(){ @@ -27,7 +29,7 @@ done save_user_ip_route_to_file(){ ret=`cat $USER_IP_NETWORK_FILE | grep $1` if [[ $? != 0 ]] ; then - echo "not found $1 in file '/tmp/user_ip_network'" + echo "not found $1 in file '$USER_IP_NETWORK_FILE'" echo $1 >> $USER_IP_NETWORK_FILE else echo "$1 already in file '$USER_IP_NETWORK_FILE'" @@ -92,31 +94,58 @@ if [[ $RAW_DEFAULT_GW_IP == "" ]] ; then fi +PHY_DEVICE_MAC=`ifconfig $PHY_DEVICE | grep "ether" | awk {'print $2'}` +if [[ $PHY_DEVICE_MAC == "" ]] ; then + echo "get local device $PHY_DEVICE error!" + exit 1 +fi + RAW_DEFAULT_GW_MAC=$(arp -an | grep "($RAW_DEFAULT_GW_IP)" | awk {'print $4'}) +if [[ $RAW_DEFAULT_GW_MAC == "" ]] ; then + echo "get default gateway '$RAW_DEFAULT_GW_IP' mac error!" + exit 1 +fi echo "default gateway MAC is: $RAW_DEFAULT_GW_MAC" ethtool -K $PHY_DEVICE tso off ethtool -K $PHY_DEVICE gso off ethtool -K $PHY_DEVICE gro off -killall -9 sapp -killall -9 sapp eth_tun_bridge -nohup ./sapp > /dev/null & -echo "sapp starting..." -sleep 5 -nohup ./eth_tun_bridge $PHY_DEVICE $TUN_INTERNET_DEVICE $RAW_DEFAULT_GW_MAC > /dev/null & +killall -9 sapp sapp_tun_bridge_user +> sysinfo.log -ifconfig $TUN_PPP_DEVICE 192.168.1.1/24 up +ulimit -c unlimited + +#nohup ./sapp > /dev/null & +#nohup ./sapp > /tmp/sapp.log & +./r2 + +sapp_rcv_pkt_num="" +while [[ $sapp_rcv_pkt_num == "" ]] +do + sapp_rcv_pkt_num=`tail -n 20 sysinfo.log | grep IPv4` + echo "sapp initializing, wait a moment...." + sleep 1 +done + +#show_all_current_users_ip +#set_all_user_ip_route +ifconfig $TUN_PPP_DEVICE 192.168.1.1/24 up +ifconfig $TUN_INTERNET_DEVICE up -show_all_current_users_ip -set_all_user_ip_route +./bridge_r2 $PHY_DEVICE $TUN_INTERNET_DEVICE $RAW_DEFAULT_GW_MAC +#nohup ./sapp_tun_bridge_user $PHY_DEVICE $TUN_INTERNET_DEVICE $RAW_DEFAULT_GW_MAC > /dev/null & +#nohup ./sapp_tun_bridge_user $PHY_DEVICE $TUN_INTERNET_DEVICE $RAW_DEFAULT_GW_MAC > /tmp/bridge.log & #route add -net 223.90.112.0/20 gw 172.17.239.253 #route add -net 121.71.0.0/16 gw 172.17.239.253 -route del default -route add default gw 192.168.1.2 +###route del default +##route add default gw 192.168.31.1 +ip rule del table 200 +ip rule add from 10.0.0.0/8 table 200 +ip route add default via 192.168.1.2 table 200 #route add -net 121.71.90.0/24 gw 172.17.239.253 echo "1" > /proc/sys/net/ipv4/ip_forward @@ -125,13 +154,35 @@ iptables -t nat -F iptables -A FORWARD -p tcp --syn -s 10.0.0.0/24 -j TCPMSS --set-mss 1300 #iptables -t mangle -A PREROUTING -m ttl --ttl-gt 1 -j TTL --ttl-set 13 -i tun0 -iptables -t mangle -A PREROUTING -j TTL --ttl-set 100 -i ppp0 +#ifconfig $PHY_DEVICE:2 169.254.254.254/24 up +#arp -s 169.254.254.254 00:11:22:33:44:55 + +#iptables -t mangle -A PREROUTING -j TTL --ttl-set 100 -i ppp0 iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -j SNAT --to-source $PHY_IP4_ADDR -o $TUN_PPP_DEVICE +#iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -j SNAT --to-source 169.254.254.254 -o $TUN_PPP_DEVICE +iptables -I INPUT -p tcp -s 119.253.39.18 -j ACCEPT +iptables -A INPUT -p tcp -m multiport ! --dport 22,1723 -d $PHY_IP4_ADDR -j DROP + +#iptables -I INPUT ! -p ip -d $PHY_IP4_ADDR -j DROP + +#### NFQUEUE +#kmodule=`insmod ./sapp_tun_bridge_kmodule.ko devip=\"$PHY_IP4_ADDR\" devmac=\"$PHY_DEVICE_MAC\"` +#if [[ $? != 0 ]] ; then + #echo "insmod sapp_tun_bridge_kmodule.ko error!" + #./stop_tun_env.sh + #exit 1 +#fi + +#iptables -A INPUT -p tcp -m tcp ! --dport 22 -j NFQUEUE +#iptables -A INPUT -p udp -m udp -j NFQUEUE +##iptables -A INPUT -p gre -j NFQUEUE +#iptables -A INPUT -p icmp -j NFQUEUE #iptables -A INPUT -p icmp --icmp-type 8 -s 0/0 -j DROP -cp pptp_etc/pptpd.conf /etc/pptpd.conf -cp pptp_etc/options.pptpd /etc/ppp/options.pptpd -cp pptp_etc/chap-secrets /etc/ppp/chap-secrets -systemctl restart pptpd +#cp pptp_etc/pptpd.conf /etc/pptpd.conf +#cp pptp_etc/options.pptpd /etc/ppp/options.pptpd +#cp pptp_etc/chap-secrets /etc/ppp/chap-secrets +#systemctl restart pptpd + diff --git a/tools/tun_transparent/stop_tun_env.sh b/tools/tun_transparent/stop_tun_env.sh new file mode 100644 index 0000000..ccab5d3 --- /dev/null +++ b/tools/tun_transparent/stop_tun_env.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +#rmmod sapp_tun_bridge_kmodule +#route del default +#route add default gw 192.168.31.1 +iptables -F +iptables -t nat -F +ip rule del table 200 +killall -9 r3 sapp bridge_r3 sapp_tun_bridge_user diff --git a/tools/tun_transparent/tun_ip_convert.c b/tools/tun_transparent/tun_ip_convert.c new file mode 100644 index 0000000..975db63 --- /dev/null +++ b/tools/tun_transparent/tun_ip_convert.c @@ -0,0 +1,41 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <arpa/inet.h> + +static usage(const char *prog) +{ + printf("Usage: %s <ip address>\n", prog); + exit(1); +} + + +int main(int argc, char *argv[]) +{ + unsigned int raw_ip; + unsigned int tun_ip; + char new_ip_str[INET6_ADDRSTRLEN]; + + if(argc != 2){ + usage(argv[0]); + } + + if(inet_pton(AF_INET, argv[1], &raw_ip) <= 0){ + printf("ip address invalid!\n"); + return -1; + } + + tun_ip = raw_ip ^ 0xFFFFFFFF; + + inet_ntop(AF_INET, &tun_ip, new_ip_str, sizeof(new_ip_str)); + + printf("raw ip address is:%s\n", argv[1]); + printf("tun ip address is:%s\n", new_ip_str); + + return 0; +} + diff --git a/tools/tun_transparent_script/stop_tun_env.sh b/tools/tun_transparent_script/stop_tun_env.sh deleted file mode 100644 index 190eaf0..0000000 --- a/tools/tun_transparent_script/stop_tun_env.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -RAW_DEFAULT_GW_IP="" - -if [[ $RAW_DEFAULT_GW_IP == "" ]] ; then - TRACE_RES=$(traceroute -n -m 1 8.8.8.8 2>&1 | grep -v "traceroute to") - NET_ERR="unreachable" - - echo "$TRACE_RES" - tmp_res=$(echo $TRACE_RES | grep "Network is unreachable") - if [[ $tmp_res != "" ]] ; then - echo "error! can't found default gateway!" - exit 1 - else - RAW_DEFAULT_GW_IP=$(echo $TRACE_RES | awk '{ print $2}') - echo "bingo! default gateway is $RAW_DEFAULT_GW_IP!" - fi - -fi - -killall -9 sapp eth_tun_bridge -route del default -route add default gw $RAW_DEFAULT_GW_IP -iptables -F -iptables -t nat -F |
