1 Star 0 Fork 3

chet_jc/kcp2raw

forked from tpu/kcp2raw 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
rawio.c 11.87 KB
一键复制 编辑 原始数据 按行查看 历史
tpu 提交于 2020-12-04 14:14 . auto add firewall rule
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
#include "main.h"
#include <pcap.h>
/******************************************************************************/
typedef struct ip_hdr_t
{
u8 h_len:4; // length of header
u8 version:4; // Version of IP
u8 tos; // Type of service
u16 total_len; // total length of the packet
u16 ident; // unique identifier
u16 frag_and_flags; // flags
u8 ttl; // ttl
u8 proto; // protocol(TCP ,UDP etc)
u16 checksum; // IP checksum
u32 src_ip;
u32 dst_ip;
}ip_hdr;
typedef struct icmp_hdr_t
{
u8 type;
u8 code;
u16 cksum;
u16 id;
u16 seq;
}icmp_hdr;
typedef struct udp_hdr_t
{
u16 src_port;
u16 dst_port;
u16 total_len;
u16 cksum;
}udp_hdr;
typedef struct rawio_tunnel_t {
// 远端ip与port
struct sockaddr_in baddr;
int timeout;
// for icmp
int id;
int seq;
// for kcp
void *ktun;
}rawio_tunnel;
#define TUNNEL_TIMEOUT 10
// 用于icmp收包
static pcap_t *pcap_fp;
// rawio端口
static SOCKET rawio_socket;
// 客户端使用
static rawio_tunnel *client_tun;
static int client_state;
// 服务端使用
#define MAX_TUNNEL 64
static rawio_tunnel *server_tun[MAX_TUNNEL];
// 服务端反向代理时使用
static rawio_tunnel *listen_tun;
static pthread_t recv_tid;
static void (*stream_recv_cb)(void *tun, const void *buf, int len);
static void *stream_recv_arg;
static u32 magic_pkt[2] = {0x76057810, 0x37219527};
/******************************************************************************/
static int npcap_init(char *devname)
{
pcap_if_t *alldevs;
pcap_if_t *d = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
int found = 0;
struct in_addr iaddr, daddr;
printf("npcap_init ...\n");
if(devname==NULL){
printf("No interface ip!\n");
return -1;
}
iaddr.s_addr = inet_addr(devname);
/* Retrieve the device list */
if(pcap_findalldevs(&alldevs, errbuf) == -1){
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
for(d=alldevs; d; d=d->next){
pcap_addr_t *addr =d->addresses;
while(addr){
daddr = ((struct sockaddr_in*)addr->addr)->sin_addr;
if(iaddr.s_addr == daddr.s_addr){
printf("Use %s (%s)\n", d->name, d->description);
found = 1;
break;
}
addr = addr->next;
}
if(found)
break;
}
if(d==NULL){
printf("No interface found(%s)!\n", devname);
return -1;
}
pcap_fp = pcap_open_live(d->name, 65536, 0, 10, errbuf);
if(pcap_fp==NULL){
printf("\nUnable to open the adapter!\n");
return -3;
}
struct bpf_program fcode;
char filter[64];
if(gcfg.run_mode==CLIENT_MODE)
sprintf(filter, "icmp[0] = 0x%02x and icmp[1] = 0x70", SERVER_PROTO);
else
sprintf(filter, "icmp[0] = 0x%02x and icmp[1] = 0x70", CLIENT_PROTO);
if(pcap_compile(pcap_fp, &fcode, filter, 1, PCAP_NETMASK_UNKNOWN)<0){
printf("\nError compiling filter: wrong syntax.\n");
pcap_close(pcap_fp);
return -4;
}
pcap_setfilter(pcap_fp, &fcode);
if(gcfg.run_mode==SERVER_MODE){
int retv;
printf("Check firewall rules ...\n");
#if defined(__linux__)
retv = system("iptables -C INPUT -p icmp --icmp-type 0x08/0x70 -j DROP");
if(retv){
retv = system("iptables -A INPUT -p icmp --icmp-type 0x08/0x70 -j DROP");
if(WEXITSTATUS(retv)){
printf("\n Add iptable rules failed!\n");
exit(-1);
}else{
printf("Add firewall rule done.\n");
}
}
#elif defined(__WIN32__)
retv = system("netsh advfirewall firewall show rule name=kkicmp");
if(retv){
retv = system("netsh advfirewall firewall add rule name=kkicmp protocol=icmpv4:8,112 dir=in action=block");
if(retv){
printf("Please add firewall rule with Administrator:\n");
printf(" netsh advfirewall firewall add rule name=kkicmp protocol=icmpv4:8,112 dir=in action=block\n");
exit(-1);
}else{
printf("Add firewall rule done.\n");
}
}
#endif
}
return 0;
}
/******************************************************************************/
char *rawio_tunnel_type(void)
{
if(gcfg.raw_mode==RAWMODE_ICMP)
return "ICMP";
else if(gcfg.raw_mode==RAWMODE_UDP)
return "UDP";
else if(gcfg.raw_mode==RAWMODE_FAKETCP)
return "FAKETCP";
else
return "Unknow";
}
static rawio_tunnel *new_rawio_tunnel(u32 peer_addr, int id)
{
rawio_tunnel *tun;
tun = (rawio_tunnel*)malloc(sizeof(rawio_tunnel));
tun->baddr.sin_family = AF_INET;
if(gcfg.raw_mode!=RAWMODE_ICMP){
tun->baddr.sin_port = htons(id);
}else{
tun->baddr.sin_port = 0;
}
tun->baddr.sin_addr.s_addr = peer_addr;
tun->id = id;
tun->seq = 0;
tun->ktun = new_kcp_tunnel(tun, stream_recv_cb, stream_recv_arg);
return tun;
}
static void add_tunnel(rawio_tunnel *tun)
{
int i;
for(i=0; i<MAX_TUNNEL; i++){
if(server_tun[i]==NULL){
server_tun[i] = tun;
return;
}
}
printf("Too many tunnel!\n");
}
static rawio_tunnel *find_tunnel(u32 paddr, int id)
{
int i;
for(i=0; i<MAX_TUNNEL; i++){
if(server_tun[i]==NULL)
continue;
if((server_tun[i]->baddr.sin_addr.s_addr == paddr) && (server_tun[i]->id == id))
return server_tun[i];
}
return NULL;
}
static void close_tunnel(rawio_tunnel *tun)
{
printf("Close %s tunnel from %s:%d\n", rawio_tunnel_type(), inet_ntoa(tun->baddr.sin_addr), ntohs(tun->baddr.sin_port));
close_tunnel_stream(tun->ktun);
close_kcp_tunnel(tun->ktun);
free(tun);
}
void *rawio_listen_tun(void)
{
if(listen_tun)
return listen_tun->ktun;
return NULL;
}
/******************************************************************************/
static void rawio_input(u32 src_addr, u32 src_port, u8 *buf, int len)
{
rawio_tunnel *tun;
struct in_addr saddr;
saddr.s_addr = src_addr;
//hex_dump("rawio_input", buf, len);
u32 *ph = (u32*)buf;
if(len==sizeof(magic_pkt) && ph[0]==magic_pkt[0] && ph[1]==magic_pkt[1]){
// 长度为0的包是connect包.
if(gcfg.run_mode==SERVER_MODE){
tun = find_tunnel(src_addr, src_port);
if(tun==NULL){
tun = new_rawio_tunnel(src_addr, src_port);
add_tunnel(tun);
printf("New %s tunnel from %s:%d\n", rawio_tunnel_type(), inet_ntoa(saddr), src_port);
}
// 服务端回复客户端
rawio_send(tun, NULL, 0);
tun->timeout = 0;
if(gcfg.listen_port){
// 服务端反向代理
listen_tun = tun;
}
}else{
// 客户端收到回复
if(client_state==0){
printf("New %s tunnel to %s success.\n", rawio_tunnel_type(), gcfg.target_ip);
client_state = 1;
}
client_tun->timeout = 0;
}
return;
}
//printf("rawio_input: len=%d\n", len);
if(gcfg.run_mode==SERVER_MODE){
tun = find_tunnel(src_addr, src_port);
}else{
tun = client_tun;
}
tun->timeout = 0;
if(tun==NULL){
printf("Unknow %s packet: %s:%d\n", rawio_tunnel_type(), inet_ntoa(saddr), src_port);
return;
}
kcp_input(tun->ktun, buf, len);
}
void handle_udp_recv(void *tunnel)
{
struct sockaddr_in saddr;
socklen_t alen = sizeof(saddr);
u8 pbuf[1536];
int retv;
retv = recvfrom(rawio_socket, (char*)pbuf, sizeof(pbuf), 0, (struct sockaddr *)&saddr, &alen);
if(retv<0){
printf("udp_tunnel recv failed! %d\n", WSAGetLastError());
return;
}
rawio_input(saddr.sin_addr.s_addr, ntohs(saddr.sin_port), pbuf, retv);
}
/******************************************************************************/
static void npcap_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
{
ip_hdr *ip = (ip_hdr*)(bytes+14);
icmp_hdr *icmp = (icmp_hdr*)(bytes+14+20);
int len = ntohs(ip->total_len) - (20+8);
rawio_input(ip->src_ip, icmp->id, (u8*)bytes+(14+20+8), len);
}
static void *npcap_recv_thread(void *arg)
{
int retv;
while(1){
retv = pcap_loop(pcap_fp, 0, npcap_handler, stream_recv_arg);
if(retv==PCAP_ERROR){
printf("pcap_loop failed! %s\n", pcap_geterr(pcap_fp));
break;
}
}
return 0;
}
/******************************************************************************/
static int rawio_send_icmp(void *tunnel, const void *buf, int len)
{
int retv;
char sbuf[1536];
rawio_tunnel *tun = (rawio_tunnel *)tunnel;
icmp_hdr *icmp = (icmp_hdr*)sbuf;
icmp->code = 0x70;
icmp->id = tun->id;
icmp->seq = tun->seq;
if(gcfg.run_mode==CLIENT_MODE){
icmp->type = CLIENT_PROTO;
tun->seq += 1;
}else{
icmp->type = SERVER_PROTO;
}
memcpy(sbuf+8, buf, len);
icmp->cksum = 0;
icmp->cksum = ip_checksum((u16*)sbuf, len+8);
retv = sendto(rawio_socket, (const char*)sbuf, len+8, 0, (struct sockaddr *)&tun->baddr, sizeof(tun->baddr));
if(retv<=0){
printf("Error sending icmp packet: %d\n", WSAGetLastError());
return -1;
}
return 0;
}
static int rawio_send_udp(void *tunnel, const void *buf, int len)
{
rawio_tunnel *tun = (rawio_tunnel *)tunnel;
int retv;
if(buf==NULL){
buf = &retv;
len = 4;
}
retv = sendto(rawio_socket, (const char*)buf, len, 0, (struct sockaddr *)&tun->baddr, sizeof(tun->baddr));
if(retv<=0){
printf("Error sending udp packet: %d\n", WSAGetLastError());
return -1;
}
return 0;
}
int rawio_send(void *tunnel, const void *buf, int len)
{
if(buf==NULL){
buf = magic_pkt;
len = sizeof(magic_pkt);
}
if(gcfg.raw_mode==RAWMODE_ICMP){
return rawio_send_icmp(tunnel, buf, len);
}else if(gcfg.raw_mode==RAWMODE_UDP){
return rawio_send_udp(tunnel, buf, len);
}else{
return -1;
}
}
/******************************************************************************/
static void check_tunnel(void)
{
int i;
if(client_tun && client_state){
client_tun->timeout += 1;
if(client_tun->timeout >= TUNNEL_TIMEOUT){
printf("%s tunnel: remote close.\n\n", rawio_tunnel_type());
client_state = 0;
}
}
for(i=0; i<MAX_TUNNEL; i++){
if(server_tun[i]==NULL)
continue;
server_tun[i]->timeout += 1;
if(server_tun[i]->timeout >= TUNNEL_TIMEOUT){
close_tunnel(server_tun[i]);
server_tun[i] = NULL;
}
}
}
static int hb_timer = 0;
int rawio_heartbeat(int ms)
{
//printf("rawio_heartbeat!\n");
hb_timer += ms;
if(hb_timer>1000){
hb_timer = 0;
if(gcfg.run_mode == CLIENT_MODE){
// 保证1s发一个心跳包
rawio_send(client_tun, NULL, 0);
}
check_tunnel();
}
return 0;
}
/******************************************************************************/
int rawio_init(void *recv_cb, void *arg)
{
int i, retv;
memset(server_tun, 0, sizeof(server_tun));
client_tun = NULL;
listen_tun = NULL;
client_state = 0;
stream_recv_cb = recv_cb;
stream_recv_arg = arg;
// rawio_socket
struct sockaddr_in bind_addr;
if(gcfg.raw_mode==RAWMODE_ICMP){
rawio_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
}else if(gcfg.raw_mode==RAWMODE_UDP){
rawio_socket = socket(AF_INET, SOCK_DGRAM, 0);
}else{
printf("FAKETCP not support!\n");
return -1;
}
if (rawio_socket==INVALID_SOCKET) {
printf("%s socket create error! %d\n", rawio_tunnel_type(), WSAGetLastError());
return -1;
}
retv = 2*1024*1024;
setsockopt (rawio_socket, SOL_SOCKET, SO_SNDBUF, (char*)&retv, sizeof(retv));
setsockopt (rawio_socket, SOL_SOCKET, SO_RCVBUF, (char*)&retv, sizeof(retv));
socket_nonblock(rawio_socket);
if(gcfg.run_mode==SERVER_MODE && gcfg.raw_mode!=RAWMODE_ICMP){
// 服务端的TCP与UDP需要绑定监听端口
bind_addr.sin_family = AF_INET;
bind_addr.sin_port = htons(gcfg.target_port);
bind_addr.sin_addr.s_addr = INADDR_ANY;
retv = bind(rawio_socket, (struct sockaddr *)&bind_addr, sizeof(bind_addr));
if(retv){
printf("bind failed! %d\n", WSAGetLastError());
return -1;
}
}
// ICMP使用pcap收包
if(gcfg.raw_mode==RAWMODE_ICMP){
retv = npcap_init(gcfg.devname);
if(retv)
return retv;
pthread_create(&recv_tid, NULL, npcap_recv_thread, NULL);
}else if(gcfg.raw_mode==RAWMODE_UDP){
evio_add(rawio_socket, handle_udp_recv, NULL, NULL, NULL);
evio_enable(rawio_socket, EV_IN);
}
if(gcfg.run_mode==CLIENT_MODE){
// 客户端只需要一条通道. 需要提前建立并连接到服务端.
int tun_id = (gcfg.raw_mode==RAWMODE_ICMP) ? (gcfg.listen_port+gcfg.forward_port) : gcfg.target_port;
client_tun = new_rawio_tunnel(inet_addr(gcfg.target_ip), tun_id);
if(client_tun==NULL)
return -1;
listen_tun = client_tun;
for(i=0; i<8; i++){
rawio_send(client_tun, NULL, 0);
//usleep(100000);
}
}
return 0;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/chet_jc/kcp2raw.git
git@gitee.com:chet_jc/kcp2raw.git
chet_jc
kcp2raw
kcp2raw
master

搜索帮助