RBXLegacy-src/sudppipe_modified/acpdump2.h

364 lines
10 KiB
C

/*
Copyright 2008,2009 Luigi Auriemma
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
http://www.gnu.org/licenses/gpl-2.0.txt
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include "ip2.h"
#if defined ACPDUMP_LOCK && WIN32
#include <windows.h>
#define ACPDUMP_LOCK_VAR static LONG is_writing = 0;
#define ACPDUMP_LOCK_START while(InterlockedExchange(&is_writing, 1)) Sleep(0);
#define ACPDUMP_LOCK_END InterlockedExchange(&is_writing, 0);
#else
#define ACPDUMP_LOCK_VAR
#define ACPDUMP_LOCK_START
#define ACPDUMP_LOCK_END
#endif
#define ACPDUMP_VER "0.2c"
#ifdef ACPDUMP_ADDR_STRUCT // define this one if you don't have the following struct
struct in_addr {
union {
struct { uint8_t s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { uint16_t s_w1,s_w2; } S_un_w;
uint32_t S_addr;
} S_un;
#define s_addr S_un.S_addr
#define s_host S_un.S_un_b.s_b2
#define s_net S_un.S_un_b.s_b1
#define s_imp S_un.S_un_w.s_w2
#define s_impno S_un.S_un_b.s_b4
#define s_lh S_un.S_un_b.s_b3
};
struct sockaddr_in {
int16_t sin_family;
uint16_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct sockaddr {
uint16_t sa_family;
char sa_data[14];
};
#endif
struct timevalx {
int32_t tv_sec;
int32_t tv_usec;
};
uint32_t str2ip(uint8_t *data) {
unsigned a, b, c, d;
if(!data[0]) return(0);
sscanf((char *)data, "%u.%u.%u.%u", &a, &b, &c, &d);
return((a & 0xff) | ((b & 0xff) << 8) | ((c & 0xff) << 16) | ((d & 0xff) << 24));
}
uint8_t *ip2str(uint32_t ip) {
static uint8_t data[16];
sprintf((char *)data, "%u.%u.%u.%u",
(ip & 0xff), ((ip >> 8) & 0xff), ((ip >> 16) & 0xff), ((ip >> 24) & 0xff));
return(data);
}
uint16_t net16(uint16_t num) {
int endian = 1; // big endian
if(!*(char *)&endian) return(num);
return((num << 8) | (num >> 8));
}
uint32_t net32(uint32_t num) {
int endian = 1; // big endian
if(!*(char *)&endian) return(num);
return(((num & 0xff000000) >> 24) |
((num & 0x00ff0000) >> 8) |
((num & 0x0000ff00) << 8) |
((num & 0x000000ff) << 24));
}
uint16_t in_cksum(void *data, int len, uint32_t *ret_sum) {
uint32_t sum = 0;
int i = len >> 1,
endian = 1; // big endian
uint16_t crc,
*p = (uint16_t *)data;
if(*(char *)&endian) endian = 0;
if(ret_sum) sum = *ret_sum;
while(i--) sum += *p++;
if(len & 1) sum += *p & (endian ? 0xff00 : 0xff);
if(ret_sum) *ret_sum = sum;
crc = sum = (sum >> 16) + (sum & 0xffff);
if(sum >>= 16) crc += sum;
if(!endian) crc = (crc >> 8) | (crc << 8);
return(~crc);
}
void putxx(FILE *fd, uint32_t num, int bits) {
int i,
bytes;
bytes = bits >> 3;
for(i = 0; i < bytes; i++) {
fputc(num >> (i << 3), fd);
}
}
void create_acp(FILE *fd) {
if(!fd) return;
putxx(fd, 0xa1b2c3d4, 32);
putxx(fd, 2, 16);
putxx(fd, 4, 16);
putxx(fd, 0, 32);
putxx(fd, 0, 32);
putxx(fd, 65535, 32);
putxx(fd, 1, 32);
fflush(fd);
}
void acp_dump(FILE *fd, int type, int protocol, uint32_t src_ip, uint16_t src_port, uint32_t dst_ip, uint16_t dst_port, uint8_t *data, int len, uint32_t *seq1, uint32_t *ack1, uint32_t *seq2, uint32_t *ack2) {
ACPDUMP_LOCK_VAR
struct {
struct timevalx ts;
uint32_t caplen;
uint32_t len;
} acp_pck;
static const uint8_t ethdata[14] =
"\x00\x00\x00\x00\x00\x00" /* dest */
"\x00\x00\x00\x00\x00\x00" /* source */
"\x08\x00"; /* type */
udph_pseudo udp_ps;
uint32_t crc;
iph ip;
udph udp;
tcph tcp;
icmph icmp;
igmph igmp;
int size,
tpsize,
close_tcp;
uint8_t *tp;
if(!fd) return;
if(!type && !protocol) {
protocol = 6;
} else if((type == 1) && !protocol) {
protocol = 6;
} else if((type == 2) && !protocol) {
protocol = 17;
} else if((type == 3) && !protocol) {
protocol = 255;
}
tp = NULL;
tpsize = 0;
if(type == 3) {
// SOCK_RAW
} else if(protocol == 6) {
tp = (uint8_t *)&tcp;
tpsize = sizeof(tcph);
} else if(protocol == 17) {
tp = (uint8_t *)&udp;
tpsize = sizeof(udph);
} else if(protocol == 1) {
tp = (uint8_t *)&icmp;
tpsize = sizeof(icmph);
} else if(protocol == 2) {
tp = (uint8_t *)&igmp;
tpsize = sizeof(igmph);
}
close_tcp = 0;
if(len < 0) {
close_tcp = 1;
len = 0;
}
if((type == 3) && (protocol == 255)) {
// SOCK_RAW, IPPROTO_RAW
size = len;
} else {
size = sizeof(iph) + tpsize + len;
}
if((sizeof(acp_pck) + sizeof(ethdata) + size) > 0xffff) { // divides the packet if it's too big
size = len; // use size as new "len" so acp_dump can be called with the same arguments
if((type == 3) && (protocol == 255)) {
len = 0xffff - (sizeof(acp_pck) + sizeof(ethdata));
} else {
len = 0xffff - (sizeof(acp_pck) + sizeof(ethdata) + sizeof(iph) + tpsize);
}
while(size > 0) {
if(size < len) len = size;
acp_dump(fd, type, protocol, src_ip, src_port, dst_ip, dst_port, data, len, seq1, ack1, seq2, ack2);
size -= len;
data += len;
}
return;
}
// use the following if gettimeofday doesn't exist on Windows
acp_pck.ts.tv_sec = time(NULL);
//acp_pck.ts.tv_usec = GetTickCount();
acp_pck.caplen = sizeof(ethdata) + size;
acp_pck.len = sizeof(ethdata) + size;
ip.ihl_ver = 0x45;
ip.tos = 0;
ip.tot_len = net16(size);
ip.id = net16(1);
ip.frag_off = net16(0);
ip.ttl = 128;
ip.protocol = protocol;
ip.check = net16(0);
ip.saddr = src_ip;
ip.daddr = dst_ip;
ip.check = net16(in_cksum((uint8_t *)&ip, sizeof(iph), NULL));
if(!tp) {
// SOCK_RAW
} else if(protocol == 6) {
tcp.source = src_port;
tcp.dest = dst_port;
tcp.seq = net32(*seq1);
tcp.ack_seq = net32(*ack1);
tcp.doff = sizeof(tcph) << 2;
if(close_tcp) {
tcp.flags = TH_RST | TH_FIN | TH_ACK;
} else if((*seq1 == 1) && (*ack1 == 0)) {
tcp.flags = TH_SYN;
} else if((*seq1 == 1) && (*ack1 == 2)) {
tcp.flags = TH_SYN | TH_ACK;
} else if((*seq1 == 2) && (*ack1 == 2) && !data) {
tcp.flags = TH_ACK;
} else {
tcp.flags = TH_PSH | TH_ACK;
*ack2 = *seq1;
(*seq1) += len;
}
tcp.window = net16(65535);
tcp.check = net16(0);
tcp.urg_ptr = net16(0);
} else if(protocol == 17) {
udp.source = src_port;
udp.dest = dst_port;
udp.check = net16(0);
udp.len = net16(sizeof(udph) + len);
udp_ps.saddr = ip.saddr;
udp_ps.daddr = ip.daddr;
udp_ps.zero = 0;
udp_ps.protocol = 17;
udp_ps.length = udp.len;
crc = 0; in_cksum(&udp_ps, sizeof(udph_pseudo), &crc);
in_cksum(&udp, sizeof(udph), &crc);
udp.check = net16(in_cksum(data, len, &crc));
} else if(protocol == 1) {
memset(&icmp, 0, sizeof(icmph));
icmp.icmp_type = 8;
icmp.icmp_code = 0;
crc = 0; in_cksum(&icmp, sizeof(udph_pseudo), &crc);
icmp.icmp_cksum = net16(in_cksum(data, len, &crc));
} else if(protocol == 2) {
igmp.igmp_type = 0x11;
igmp.igmp_code = 0;
igmp.igmp_cksum = net16(0);
igmp.igmp_group = net32(0);
crc = 0; in_cksum(&igmp, sizeof(udph_pseudo), &crc);
igmp.igmp_cksum = net16(in_cksum(data, len, &crc));
}
ACPDUMP_LOCK_START
fwrite(&acp_pck, sizeof(acp_pck), 1, fd);
fwrite(ethdata, sizeof(ethdata), 1, fd);
if(!((type == 3) && (protocol == 255))) {
fwrite(&ip, sizeof(iph), 1, fd);
}
if(tp) fwrite(tp, tpsize, 1, fd);
fwrite(data, len, 1, fd);
fflush(fd);
ACPDUMP_LOCK_END
}
void acp_dump_handshake(FILE *fd, int type, int protocol, uint32_t src_ip, uint16_t src_port, uint32_t dst_ip, uint16_t dst_port, uint8_t *data, int len, uint32_t *seq1, uint32_t *ack1, uint32_t *seq2, uint32_t *ack2) {
if(!fd) return;
if(!seq1 || !ack1 || !seq2 || !ack2) return;
*seq1 = 0; // useless initialization
*ack1 = 0;
*seq2 = 0;
*ack2 = 0;
if(!((!type && !protocol) || ((type == 1) && !protocol) || (protocol == 6))) {
return; // if it's not tcp don't make handshake
}
*seq1 = 1;
*ack1 = 0;
acp_dump(fd, type, protocol, src_ip, src_port, dst_ip, dst_port, NULL, 0, seq1, ack1, seq2, ack2);
*ack2 = *seq1 + 1;
*seq2 = 1;
acp_dump(fd, type, protocol, dst_ip, dst_port, src_ip, src_port, NULL, 0, seq2, ack2, seq1, ack1);
*ack1 = *seq2 + 1;
(*seq1)++;
acp_dump(fd, type, protocol, src_ip, src_port, dst_ip, dst_port, data, len, seq1, ack1, seq2, ack2);
(*seq2)++;
}