根据要求,我已将代码全部包含在内,以便您对其进行测试。请记住,这还远未完成,但应该能够通过稳定的 tcp 连接发送和接收数据包。
当我运行它时,我得到:
./bunny -i 84.49.76.98 -p 80 -o 79.161.200.48 -t 80
Raw packet reader created
Waiting 1 second for packet reader thread to settle down...
socket() - Using SOCK_RAW and TCP protocol is OK.
Socketoptions OK.
然后它就挂了。我也使用了 strace ,这给了我(只包括它停止的最后一点):
setsockopt(4, SOL_IP, IP_HDRINCL, [1], 4) = 0
write(1, "Socketoptions OK.\n", 18Socketoptions OK.
) = 18
sendto(4, "", 0, 0, {sa_family=AF_INET, sin_port=htons(63239), sin_addr=inet_addr("84.49.76.98")}, 16) = 0
close(4) = 0
futex(0x7f4c07bf89d0, FUTEX_WAIT, 3278, NULLsendto(4, "", 0, 0, {sa_family=AF_INET, sin_port=htons(63239), sin_addr=inet_addr("84.49.76.98")}, 16) = 0
close(4) = 0
并且系统监视器说程序正在休眠,并给出 futex_wait_queue_me。
这可能是由于某处的内存泄漏导致对 futex 的调用过多吗?
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <pcap.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#define VERSION "1.0"
#define PCKT_LEN 8192
/* Prototypes */
int sock;
void run();
void capture();
void usage();
in_addr_t sip;
in_addr_t dip;
char *dstip = 0;
int s_seq;
int sport;
int dport;
struct pseudo {
struct in_addr sourceip;
struct in_addr destip;
unsigned char placeholder;
unsigned char protocol;
unsigned char tcp_len;
struct tcphdr tcp;
};
struct ipheader {
unsigned char iph_ihl:5,
iph_ver:4;
unsigned char iph_tos;
unsigned short int iph_len;
unsigned short int iph_id;
unsigned char iph_flags;
unsigned short int iph_offset;
unsigned char iph_ttl;
unsigned char iph_protocol;
unsigned short int iph_chksum;
unsigned int iph_sourceip;
unsigned int iph_destip;
};
struct tcpheader {
unsigned short int tcph_sourceport;
unsigned short int tcph_destport;
unsigned int tcph_seqnum;
unsigned int tcph_acknum;
unsigned char tcph_reserved:4, tcph_offset:4;
unsigned char tcph_flags;
unsigned short int tcph_win;
unsigned short int tcph_chksum;
unsigned short int tcph_urgptr;
};
/* Checksum */
unsigned short checksum (unsigned short *pac, int len)
{
unsigned long sum;
for (sum = 0; len > 0; len--)
sum += *pac++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return(~sum);
}
/* Checksum TCP */
unsigned short checksum_tcp (unsigned short len, unsigned short sourceip[],
unsigned short destip[], unsigned short buf[])
{
unsigned char protocol = 6;
unsigned long sum;
int nleft;
unsigned short *w;
sum = 0;
nleft = len;
w=buf;
while(nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if(nleft > 0)
{
sum += *w&ntohs(0xFF00);
}
sum += sourceip[0];
sum += sourceip[1];
sum += destip[0];
sum += destip[1];
sum += htons(len);
sum += htons(protocol);
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
sum = ~sum;
return ((unsigned short) sum);
}
int main(int argc,char **argv)
{
int c;
/* Are we in root? */
if(geteuid() !=0)
{
printf("Root access is required to run this program.\n\n");
exit(0);
}
while (1)
{
static struct option long_options[] =
{
/* Options */
{"send", no_argument, 0, 's'}, /* args s, r and f have no function yet */
{"receive", no_argument, 0, 'r'},
{"file", required_argument, 0, 'f'},
{"destip", required_argument, 0, 'i'},
{"destport", required_argument, 0, 'p'},
{"sourceip", required_argument, 0, 'o'},
{"sourceport", required_argument, 0, 't'},
{0, 0, 0, 0}
};
int option_index = 0;
c = getopt_long (argc, argv, "srf:d:i:p:o:t:",
long_options, &option_index);
/* Detect the end of the options. */
if (c == -1)
break;
switch (c)
{
case 0: /* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0)
break;
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case 's': puts ("option -s\n");
break;
case 'r': puts ("option -r\n");
break;
case 'f': printf ("option -f with value `%s'\n", optarg);
break;
case 'i': dip = inet_addr(optarg);
dstip = optarg;
break;
case 'p': dport = htons(atoi(optarg));
/* Add handling of bad/non number input here */
break;
case 'o': sip = inet_addr(optarg);
break;
case 't': sport = htons(atoi(optarg));
break;
case '?': /* Error message printed */
break;
default: abort ();
}
}
/* Print any remaining command line arguments (not options). */
if (optind < argc)
{
printf ("\nNon-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
putchar ('\n');
}
/* check if all mandatory options are set and for unknown arguments */
/* This really needs changing... */
if (dip, sip, dport, sport == 0)
{
usage();
return (-1);
}
/* change */
pthread_t tid_pr;
if (pthread_create(&tid_pr, NULL, capture, NULL) != 0) {
fprintf(stderr, "can't create raw packet reader: %s\n", strerror(errno));
exit(1);
}
printf("\nRaw packet reader created\nWaiting 1 second for packet reader thread to settle down...\n\n");
sleep(1);
run();
pthread_join(tid_pr, NULL);
getchar ();
exit (0);
}
int send_syn(unsigned int sourceip, unsigned int destip, unsigned short sourceport,
unsigned short destport)
{
const int one = 1;
char buffer[PCKT_LEN];
struct sockaddr_in sin;
struct ipheader *ip;
struct tcpheader *tcp;
ip = (struct ipheader *) buffer;
tcp = (struct tcpheader *) buffer + ip->iph_ihl *4;
/* IP attributes */
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
ip->iph_len = sizeof(struct ipheader) + sizeof(struct tcpheader);
ip->iph_id = htons(54321);
ip->iph_offset = 0;
ip->iph_ttl = 64;
ip->iph_protocol = IPPROTO_TCP;
ip->iph_chksum = 0;
ip->iph_sourceip = sip;
ip->iph_destip = dip;
ip->iph_chksum = checksum ((unsigned short *) buffer, (sizeof (struct
ipheader )+ sizeof (struct tcpheader)));
/* TCP attributes */
tcp->tcph_sourceport = sport;
tcp->tcph_destport = dport;
tcp->tcph_seqnum = htonl(1); /* ADD SEQ NUM THINGY */
tcp->tcph_offset = 5;
tcp->tcph_flags = TH_SYN;
tcp->tcph_win = htons(32767);
tcp->tcph_chksum = 0;
tcp->tcph_urgptr = 0;
tcp->tcph_chksum = (unsigned short) checksum_tcp((unsigned short) (ip->iph_len - ip->iph_ihl *4), (unsigned short *) &ip->iph_sourceip,
(unsigned short *) &ip->iph_destip, (unsigned short *) &tcp);
/* Address family */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip->iph_destip;
/* Send */
if (sendto(sock, buffer, ip->iph_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
fprintf(stderr, "\nCan't send packet\n");
return (-1);
}
else
printf("Packet sent to %d", dip);
close(sock);
}
int send_syn_ack(unsigned int sourceip, unsigned int destip, unsigned short sourceport,
unsigned short destport, unsigned long s_seq)
{
const int one = 1;
char buffer[PCKT_LEN];
struct sockaddr_in sin;
struct ipheader *ip;
struct tcpheader *tcp;
ip = (struct ipheader *) buffer;
tcp = (struct tcpheader *) buffer + ip->iph_ihl *4;
/* IP attributes */
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
ip->iph_len = sizeof(struct ipheader) + sizeof(struct tcpheader);
ip->iph_id = htons(54321);
ip->iph_offset = 0;
ip->iph_ttl = 64;
ip->iph_protocol = IPPROTO_TCP;
ip->iph_chksum = 0;
ip->iph_sourceip = sip;
ip->iph_destip = dip;
ip->iph_chksum = checksum ((unsigned short *) buffer, (sizeof (struct
ipheader )+ sizeof (struct tcpheader)));
/* TCP attributes */
tcp->tcph_sourceport = sport;
tcp->tcph_destport = dport;
tcp->tcph_seqnum = htonl(1 + 1); /* ADD SEQ NUM THINGY */
tcp->tcph_acknum = htonl (s_seq + 1); /* ADD ACK NUM THINGY */
tcp->tcph_offset = 5;
tcp->tcph_flags = TH_ACK;
tcp->tcph_win = htons(32767);
tcp->tcph_chksum = 0;
tcp->tcph_urgptr = 0;
tcp->tcph_chksum = (unsigned short) checksum_tcp((unsigned short) (ip->iph_len - ip->iph_ihl *4), (unsigned short *) &ip->iph_sourceip,
(unsigned short *) &ip->iph_destip, (unsigned short *) &tcp);
/* Address family */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip->iph_destip;
/* Send */
if (sendto(sock, buffer, ip->iph_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
fprintf(stderr, "\nCan't send packet\n");
return (-1);
}
else
printf("Packet sent to %d\n", dip);
close(sock);
}
void run()
{
const int one = 1;
char buffer[PCKT_LEN];
struct sockaddr_in sin;
struct ipheader *ip;
struct tcpheader *tcp;
ip = (struct ipheader *) buffer;
tcp = (struct tcpheader *) buffer + ip->iph_ihl *4;
sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
if (sock < 0)
{
fprintf(stderr, "\nSocket()\n\n");
exit (-1);
}
else
printf ("socket() - Using SOCK_RAW and TCP protocol is OK.\n");
if ((setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof (one))) < 0)
{
fprintf(stderr, "Can't set socketoptions\n");
exit (-1);
}
else
printf("Socketoptions OK.\n");
send_syn(dip, sip, dport, sport);
}
void receive(u_char *args, const struct pcap_pkthdr *pkthdr, const u_char *buffer)
{
const int one = 1;
int LEN = strtol(args, NULL, 0); /* LEN = strtol(args, NULL, 0) ---- int LEN = *args;*/
struct ipheader *ip;
struct tcpheader *tcp;
ip = (struct ipheader *)(buffer + LEN);
tcp = (struct tcpheader *)(buffer + LEN + sizeof (struct ipheader));
printf("%d\n", LEN);
printf("Packet received. ACK number: %d\n", ntohl (tcp->tcph_seqnum));
printf("Packet received. SEQ number: %d\n", ntohl (tcp->tcph_acknum));
s_seq = ntohl (tcp->tcph_seqnum);
send_syn_ack(s_seq, dip, sip, dport, sport);
sleep(100);
}
void capture()
{
pcap_t *pd;
bpf_u_int32 netmask;
bpf_u_int32 localnet;
char filterbuf[64];
snprintf(filterbuf, sizeof(filterbuf), "ip dst host %s", dstip);
char *filter = filterbuf;
char *dev = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program filterprog;
int dl = 0, dl_len = 0;
if ((pd = pcap_open_live(dev, 1514, 1, 500, errbuf)) == NULL) /* Look into snaplen size */
{
fprintf(stderr, "can't open device %s: %s\n", dev, errbuf);
exit(1);
}
pcap_lookupnet(dev, &localnet, &netmask, errbuf);
pcap_compile(pd, &filterprog, filter, 0, localnet);
if (pcap_setfilter(pd, &filterprog) == - 1)
{
fprintf(stderr, "can't set pcap filter: %s %s\n", filter, errbuf);
exit(1);
}
pcap_freecode(&filterprog);
dl = pcap_datalink(pd);
switch(dl) {
case 1:
dl_len = 14;
break;
default:
dl_len = 14;
break;
}
if (pcap_loop(pd, -1, receive, (u_char *) &dl_len) < 0)
{
fprintf(stderr, "can't get raw packet: %s\n", pcap_geterr(pd));
exit(1);
}
}
void usage()
{
/* This is the user manual (CHANGE) */
printf("\nChannelBunny %s, created 2012\n\n", VERSION);
printf("ChannelBunny Usage: -s -f <file> -i <destip> -p <destport> -o <sourceip> -t <sourceport>\n\n");
printf("-s, --send, Puts program in send mode\n");
printf("-r, --receive, Puts program in receive mode\n");
printf("-f, --file, Specify file\n");
printf("-i, --destip, Destination IP address\n");
printf("-p, --destport, Destination port\n");
printf("-o, --sourceip Source IP address\n");
printf("-t, --sourceport Source port\n");
}