summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlijia <[email protected]>2020-03-18 22:01:54 +0800
committerlijia <[email protected]>2020-03-18 22:01:54 +0800
commit2e6da7600c366f3ff36d4d4db3cabcd245b5c3ec (patch)
tree10d5be75c061ccf41626d103a092141e2438b3fa
parent1d23241d7bb60cb443a521c2ed5281190d3f096e (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.c8
-rw-r--r--src/packet_io/packet_io_tun.c88
-rw-r--r--src/packet_io/sendpacket.c5
-rw-r--r--test/Makefile1
-rw-r--r--test/test_app_sapp.c67
-rw-r--r--tools/tun_transparent/Makefile13
-rw-r--r--tools/tun_transparent/Makefile.user38
-rw-r--r--tools/tun_transparent/bridge_r25
-rw-r--r--tools/tun_transparent/bridge_r317
-rw-r--r--tools/tun_transparent/sapp_tun_bridge_kmodule.c396
-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.sh9
-rw-r--r--tools/tun_transparent/tun_ip_convert.c41
-rw-r--r--tools/tun_transparent_script/stop_tun_env.sh25
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