通常我们检测rtt和丢包率是采用ping(利用icmp请求响应报文),这里提供了一种采用tcp的方式计算rtt和丢包率。原理比较简单,利用tcp raw socket自己封装tcp syn报文,接收对方发过的syn+ack报文,以此来计算平滑rtt和丢包率。当前只实现了一对一的扫描,发送端需要绑定本地IP和一个端口,默认是选择的80端口,当然还需要指定对端IP和端口(默认也是80)。整个实现逻辑比较原始,串行扫描,使用sendto接口发送报文,recvfrom接口接收报文,实际上利用pcap库来接收效率更高。另外也没有利用类似epoll这样的异步模型。在第二版的时候我要改成基于epoll的异步模型。在第三版的时候可以实现一对多,这个多不是一点点,是全网上亿个IP的扫描,第二、三版代码已写完,找个时间更新在博客上。
* Author: ZuoSi<zuosi8968@gmail.com>
* Date: 2015-11-12
***********************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // close()
#include <string.h> // strcpy, memset(), and memcpy()
#include <fcntl.h>
#include <netdb.h> // struct addrinfo
#include <sys/types.h> // needed for socket(), uint8_t, uint16_t, uint32_t
#include <sys/socket.h> // needed for socket()
#include <netinet/in.h> // IPPROTO_RAW, IPPROTO_TCP, IPPROTO_ICMP, IPPROTO_UDP, INET_ADDRSTRLEN
#include <netinet/ip.h> // struct ip and IP_MAXPACKET (which is 65535)
#include <netinet/ip_icmp.h> // struct icmp and ICMP_TIME_EXCEEDED
#define __FAVOR_BSD // Use BSD format of TCP header and UDP header
#include <netinet/tcp.h> // struct tcphdr
#include <netinet/udp.h> // struct udphdr
#include <arpa/inet.h> // inet_pton() and inet_ntop()
#include <sys/ioctl.h> // macro ioctl is defined
#include <bits/ioctls.h> // defines values for argument "request" of ioctl.
#include <net/if.h> // struct ifreq
#include <linux/if_ether.h> // ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD
#include <linux/if_packet.h> // struct sockaddr_ll (see man 7 packet)
#include <net/ethernet.h>
#include <sys/time.h> // gettimeofday()
#include <getopt.h>
#include <errno.h> // errno, perror()
// Define some constants.
#define ETH_HDRLEN 14 // Ethernet header length
#define IP4_HDRLEN 20 // IPv4 header length
#define TCP_HDRLEN 20 // TCP header length, excludes options data
#define SYN_ACK 0
#define SYN_NO_ACK 1
#define NO_SYN 2
#define MAX_MSG_LEN 1024
#define TCPING_VERSION "1.0"
#define DEBUG
#ifdef DEBUG
#define DEBUG_OUTPUT(msg) ({ printf("%s", msg); })
#else
#define DEBUG_OUTPUT(msg) ({})
#endif
#define TRUE 1
#define FALSE 0
// Function prototypes
uint16_t checksum (uint16_t *, int);
uint16_t tcp4_checksum (struct ip, struct tcphdr, uint8_t *, int);
int create_ip_frame (uint8_t *, char *, uint16_t, char *, uint16_t, int, uint32_t, uint8_t *, int);
char *allocate_strmem (int);
uint8_t *allocate_ustrmem (int);
int *allocate_intmem (int);
int is_valid_ip(const char* ip)
{
int n[4];
char c[4];
if (sscanf(ip, "%d%c%d%c%d%c%d%c",
&n[0], &c[0], &n[1], &c[1],
&n[2], &c[2], &n[3], &c[3])
== 7)
{
int i;
for(i = 0; i < 3; ++i){
if (c[i] != '.')
return FALSE;
}
for(i = 0; i < 4; ++i){
if (n[i] > 255 || n[i] < 0)
return FALSE;
}
return TRUE;
} else {
return FALSE;
}
}
void
print_usage(const char *prog_name)
{
printf("%s 4.3.0\n", prog_name);
printf("This is a program stat packet lose\n");
printf("Usage: %s -s <soure_ip:source_port> -d <dest_ip:dest_port> [options]\n", prog_name);
printf(" -s --source local addr:port, e.g. 192.168.10.10,192.168.10.10:80\n");
printf(" -d --dest dest addr:port, e.g. 192.168.10.10,192.168.10.10:80\n");
printf("Options:\n");
printf(" -t --timeout response packet wait timeout(ms) e.g 200ms\n");
printf(" -c --count send packet count e.g 1000\n");
printf(" -m --multiplex set wto equal to multiplex * rtt e.g 4\n");
printf(" -v --verbose detail outout,default statistic information\n");
}
int
main (int argc, char **argv)
{
int multiplex;
float factor, ratio, rtt, rtts, wto;
int first, set_wto, set_interval, verbose;
uint32_t interval, idt, recv_again_max, again_cnt;
double dt;
int i, status, frame_length, sd, sendsd, recsd, bytes, ttl;
char rec_ip[INET_ADDRSTRLEN], src_ip[INET_ADDRSTRLEN] = {'\0'}, dst_ip[INET_ADDRSTRLEN]={'\0'};
uint32_t pack_cnt_max, pack_cnt, pack_lost;
uint32_t syn_seq, syn_ack_seq, syn_seq_timeout_skip;
int datalen;
char *tcp_dat;
uint16_t src_port, dst_port;
char hostname[NI_MAXHOST];
char msg[MAX_MSG_LEN];
struct ip *iphdr;
struct tcphdr *tcphdr;
uint8_t *snd_ip_frame, *rec_ip_frame;
uint8_t *data;
struct sockaddr_in dst_sa, src_sa;
struct sockaddr from;
struct ifreq ifr;
socklen_t fromlen;
struct timeval wait, t1, t2, ti1;
struct timezone tz;
int optval = 1;
char* port_p;
int8_t arg=0;
char *short_opts = "hV?s:d:t:c:m:i:v";
const struct option long_opts[] = {
{"help", 1, NULL, 'h'},
{"source", 1, NULL, 's'},
{"dest", 1, NULL, 'd'},
{"count", 1, NULL, 'c'},
{"timeout", 1, NULL, 't'},
{"interval", 1, NULL, 'i'},
{"verbose", 0, NULL, 'v'},
{"multiplex", 1, NULL, 'm'},
{"version", 0, NULL, 'V'}
};
multiplex = 5;
pack_cnt = 0;
pack_lost = 0;
pack_cnt_max = 1000;
wto = 1000;
set_wto = FALSE;
set_interval = FALSE;
interval = 0;
first = TRUE;
factor = 0.125;
verbose = FALSE;
src_port = dst_port = 80;
syn_seq_timeout_skip = 1000;
while((arg = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1){
switch(arg){
case 's':
port_p = strrchr(optarg, ':');
if(port_p){
if(*(port_p+1) == '\0'){
fprintf(stderr, "Error: invalid parameters %s\n", optarg);
return(EXIT_FAILURE);
}
src_port = atoi(port_p+1);
*port_p = '\0';
}
strncpy(src_ip, optarg, INET_ADDRSTRLEN);
break;
case 'd':
port_p = strrchr(optarg, ':');
if(port_p){
if(*(port_p+1) == '\0'){
fprintf(stderr, "Error: invalid parameters %s\n", optarg);
return(EXIT_FAILURE);
}
dst_port = atoi(port_p+1);
*port_p = '\0';
}
strncpy(dst_ip, optarg, INET_ADDRSTRLEN);
break;
case 't':
wto = atoi(optarg);
if(wto < 0 || wto > 5000){
fprintf(stderr, "Error: impossible timeout value, please set between 0~5000(ms)\n");
return(EXIT_FAILURE);
}
set_wto = TRUE;
break;
case 'c':
if(atoi(optarg) <= 0){
fprintf(stderr, "Error: invalid count.\n");
return(EXIT_FAILURE);
}
pack_cnt_max = atoi(optarg);
break;
case 'm':
if(atoi(optarg) <= 0){
fprintf(stderr, "Error: invalid multiplex.\n");
return(EXIT_FAILURE);
}
multiplex = atoi(optarg);
break;
case 'i':
interval = atof(optarg) * 1000;
set_interval = TRUE;
break;
case 'v':
verbose = TRUE;
break;
case 'V':
printf("version: %s\n", TCPING_VERSION);
return(EXIT_SUCCESS);
case 'h':
case '?':
print_usage(argv[0]);
return(EXIT_FAILURE);
}
}
if(!strlen(src_ip) || !strlen(dst_ip)){
print_usage(argv[0]);
return(EXIT_FAILURE);
}
if(!is_valid_ip(src_ip) || !is_valid_ip(dst_ip)){
printf("Error: invalid ip addr.\n");
return(EXIT_FAILURE);
}
// Allocate memory for various arrays.
tcp_dat = allocate_strmem (IP_MAXPACKET);
data = allocate_ustrmem (IP_MAXPACKET);
snd_ip_frame = allocate_ustrmem (IP_MAXPACKET);
rec_ip_frame = allocate_ustrmem (IP_MAXPACKET);
// Payloads for TCP packets.
strcpy (tcp_dat, "");
// SYN init sequence
syn_seq = 0;
syn_ack_seq = syn_seq + 1;
// Check for acceptable payload lengths.
if (strlen (tcp_dat) > (IP_MAXPACKET - IP4_HDRLEN - TCP_HDRLEN)) {
fprintf (stderr, "Maximum TCP data length exceeded. Maximum length is %i\n", IP_MAXPACKET - IP4_HDRLEN - TCP_HDRLEN);
exit (EXIT_FAILURE);
}
// Submit request for a raw socket descriptors - one to send, one to receive.
if ((sendsd = socket (PF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
perror ("socket() failed to obtain a send socket descriptor ");
exit (EXIT_FAILURE);
}
if(setsockopt(sendsd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval)) < 0){
perror("setsockopt failed ");
exit(EXIT_FAILURE);
}
if ((recsd = socket (PF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
perror ("socket() failed to obtain a receive socket descriptor ");
exit (EXIT_FAILURE);
}
// Set time for the socket to timeout and give up waiting for a reply.
recv_again_max = 6;
wait.tv_sec = 0;
wait.tv_usec = 500000;
setsockopt (recsd, SOL_SOCKET, SO_RCVTIMEO, (char *)&wait, sizeof(struct timeval));
memset(&src_sa, 0, sizeof(struct sockaddr_in));
inet_pton(AF_INET, src_ip, (void*)&src_sa.sin_addr);
src_sa.sin_port = htons(src_port);
if(bind(recsd, (struct sockaddr*)&src_sa, sizeof(struct sockaddr_in)) < 0){
perror("bind() failed ");
exit(EXIT_FAILURE);
}
//ttl
ttl = 64;
// LOOP: incrementing TTL each time, exiting when we get our target IP address.
iphdr = (struct ip *)rec_ip_frame;
tcphdr = (struct tcphdr *)(rec_ip_frame + IP4_HDRLEN);
(void) gettimeofday (&ti1, &tz);
for (;;) {
// Create probe packet.
memset (snd_ip_frame, 0, IP_MAXPACKET * sizeof (uint8_t));
datalen = strlen (tcp_dat);
memcpy (data, tcp_dat, datalen * sizeof (uint8_t));
create_ip_frame (snd_ip_frame, src_ip, src_port, dst_ip, dst_port, ttl, syn_seq, data, datalen);
frame_length = IP4_HDRLEN + TCP_HDRLEN + datalen;
// Send ip frame to socket.
memset(&dst_sa, 0, sizeof(struct sockaddr_in)); //notice: must init sockaddr_in zero
inet_pton(AF_INET, dst_ip, (void*)&dst_sa.sin_addr);
dst_sa.sin_family = AF_INET;
dst_sa.sin_port = htons(dst_port);
(void) gettimeofday (&t1, &tz);
if(set_interval){
idt = (t1.tv_sec - ti1.tv_sec) * 1000 + (t1.tv_usec - ti1.tv_usec) / 1000;
if(idt < interval)
usleep((interval - idt) * 1000);
// Get time again, this is very important
(void) gettimeofday (&t1, &tz);
ti1 = t1;
}
if(pack_cnt >= pack_cnt_max){
ratio = (float)pack_lost / (float)(pack_cnt_max + pack_cnt_max - pack_lost) * 100.0;
printf("\n---------tcping statistics---------\n");
printf("send : %u\n", pack_cnt_max);
printf("lost : %u\n", pack_lost);
printf("ratio : %2.4f%\n", ratio);
printf("rtts : %2.4f\n", rtts);
printf("wto : %2.4f\n", wto);
printf("addr : %s\n", dst_ip);
goto end_prog;
}
++pack_cnt;
if ((bytes = sendto (sendsd, snd_ip_frame, frame_length, 0, (struct sockaddr*)&dst_sa, sizeof(struct sockaddr_in))) <= 0) {
perror ("sendto() failed");
exit (EXIT_FAILURE);
}
// Start timer.
// Listen for incoming ip frame from socket sd.
// RECEIVE LOOP
again_cnt = 0;
for (;;) {
memset (rec_ip_frame, 0, IP_MAXPACKET * sizeof (uint8_t));
memset (&from, 0, sizeof (from));
fromlen = sizeof (from);
if ((bytes = recvfrom (recsd, rec_ip_frame, IP_MAXPACKET, 0, (struct sockaddr *)&from, &fromlen)) < 0) {
status = errno;
// Deal with error conditions first.
if (status == EAGAIN) { // EAGAIN = 11
++again_cnt;
if(again_cnt > recv_again_max){
++pack_lost;
if(verbose) {
ratio = (float)pack_lost / (float)(pack_cnt + pack_cnt - pack_lost) * 100.0;
printf ("%-u\t %-s\t\t lost\t\t %2.4fms\t %u/%u\t %2.4f\n", pack_cnt, dst_ip, wto, pack_lost, pack_cnt, ratio);
syn_seq = syn_seq + syn_seq_timeout_skip;
}
break;
}
continue; // Recv again
} else if (status == EINTR) { // EINTR = 4
continue; // Something weird happened, but let's keep listening.
} else {
perror ("recvfrom() failed.\n");
exit (EXIT_FAILURE);
}
} // End of error handling conditionals.
// Stop timer and calculate how long it took to get a reply.
(void) gettimeofday (&t2, &tz);
dt = (double)(t2.tv_sec - t1.tv_sec) * 1000.0 + (double) (t2.tv_usec - t1.tv_usec) / 1000.0;
// Check for an IP ethernet frame. If not, ignore and keep listening.
// Did we reach our destination?
if ((iphdr->ip_p == IPPROTO_TCP) && (tcphdr->th_flags == 18)) { // (18 = SYN, ACK)
// Extract source IP address from received ethernet frame.
if (inet_ntop (AF_INET, &(iphdr->ip_src.s_addr), rec_ip, INET_ADDRSTRLEN) == NULL) {
status = errno;
fprintf (stderr, "inet_ntop() failed.\nError message: %s", strerror (status));
exit (EXIT_FAILURE);
}
// Check rec ip and ack sequence
if ((strcmp(rec_ip, dst_ip) != 0) || (ntohs(tcphdr->th_dport) != src_port) || (ntohl(tcphdr->th_ack) != syn_ack_seq)) {
continue;
}
// Recv correct syn+ack packet
rtt = dt;
if(first){
rtts = rtt;
first = FALSE;
}
else{
rtts = (1.0-factor)*rtts + factor*rtt;
}
if(!set_wto)
wto = multiplex * rtts;
// Report source IP address and time for reply.
if(verbose) {
ratio = (float)pack_lost / (float)(pack_cnt + pack_cnt - pack_lost) * 100.0;
printf ("%-u\t %-s\t\t %2.4fms\t %2.4fms\t %u/%u\t %2.4f\n", pack_cnt, dst_ip, rtts, wto, pack_lost, pack_cnt, ratio);
}
syn_seq = syn_seq + 1;
break;
} // End of Reached Destination conditional.
if(dt > wto){
++pack_lost;
if(verbose) {
ratio = (float)pack_lost / (float)(pack_cnt + pack_cnt - pack_lost) * 100.0;
printf("%-u\t %-s\t\t lost\t\t %2.4fms\t %u/%u\t %2.4f\n", pack_cnt, dst_ip, wto, pack_lost, pack_cnt, ratio);
}
// reset syn init sequence
syn_seq = syn_seq + syn_seq_timeout_skip;
break;
}
} // End of Receive loop.
syn_seq = syn_seq > 655350 ? 0 : syn_seq;
syn_ack_seq = syn_seq + 1;
} // End of Send loop.
end_prog:
// Close socket descriptors.
close (sendsd);
close (recsd);
// Free allocated memory.
free (tcp_dat);
free (data);
free (snd_ip_frame);
free (rec_ip_frame);
return (EXIT_SUCCESS);
}
// Create a TCP IP frame.
int
create_ip_frame (uint8_t *snd_ip_frame, char *src_ip, uint16_t src_port, char *dst_ip, uint16_t dst_port, int ttl, uint32_t seq, uint8_t *data, int datalen)
{
int i, status, *ip_flags, *tcp_flags;
struct ip iphdr;
struct tcphdr tcphdr;
// Allocate memory for various arrays.
ip_flags = allocate_intmem (4);
tcp_flags = allocate_intmem (8);
// IPv4 header
// IPv4 header length (4 bits): Number of 32-bit words in header = 5
iphdr.ip_hl = IP4_HDRLEN / sizeof (uint32_t);
// Internet Protocol version (4 bits): IPv4
iphdr.ip_v = 4;
// Type of service (8 bits)
iphdr.ip_tos = 0;
// Total length of datagram (16 bits): IP header + TCP header + data
iphdr.ip_len = htons (IP4_HDRLEN + TCP_HDRLEN + datalen);
// ID sequence number (16 bits): unused, since single datagram
iphdr.ip_id = htons (0);
// Flags, and Fragmentation offset (3, 13 bits): 0 since single datagram
// Zero (1 bit)
ip_flags[0] = 0;
// Do not fragment flag (1 bit)
ip_flags[1] = 0;
// More fragments following flag (1 bit)
ip_flags[2] = 0;
// Fragmentation offset (13 bits)
ip_flags[3] = 0;
iphdr.ip_off = htons ((ip_flags[0] << 15)
+ (ip_flags[1] << 14)
+ (ip_flags[2] << 13)
+ ip_flags[3]);
// Time-to-Live (8 bits): default to maximum value
iphdr.ip_ttl = ttl;
// Transport layer protocol (8 bits): 6 for TCP
iphdr.ip_p = IPPROTO_TCP;
// Source IPv4 address (32 bits)
if ((status = inet_pton (AF_INET, src_ip, &(iphdr.ip_src))) != 1) {
fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
exit (EXIT_FAILURE);
}
// Destination IPv4 address (32 bits)
if ((status = inet_pton (AF_INET, dst_ip, &(iphdr.ip_dst))) != 1) {
fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
exit (EXIT_FAILURE);
}
// IPv4 header checksum (16 bits): set to 0 when calculating checksum
iphdr.ip_sum = 0;
iphdr.ip_sum = checksum ((uint16_t *) &iphdr, IP4_HDRLEN);
// TCP header
// Source port number (16 bits)
tcphdr.th_sport = htons (src_port);
// Destination port number (16 bits)
tcphdr.th_dport = htons (dst_port);
// Sequence number (32 bits)
tcphdr.th_seq = htonl (seq);
// Acknowledgement number (32 bits): 0 in first packet of SYN/ACK process
tcphdr.th_ack = htonl (seq + 1);
// Reserved (4 bits): should be 0
tcphdr.th_x2 = 0;
// Data offset (4 bits): size of TCP header in 32-bit words
tcphdr.th_off = TCP_HDRLEN / 4;
// Flags (8 bits)
// FIN flag (1 bit)
tcp_flags[0] = 0;
// SYN flag (1 bit): set to 1
tcp_flags[1] = 1;
// RST flag (1 bit)
tcp_flags[2] = 0;
// PSH flag (1 bit)
tcp_flags[3] = 0;
// ACK flag (1 bit)
tcp_flags[4] = 0;
// URG flag (1 bit)
tcp_flags[5] = 0;
// ECE flag (1 bit)
tcp_flags[6] = 0;
// CWR flag (1 bit)
tcp_flags[7] = 0;
tcphdr.th_flags = 0;
for (i=0; i<8; i++) {
tcphdr.th_flags += (tcp_flags[i] << i);
}
// Window size (16 bits)
tcphdr.th_win = htons (65535);
// Urgent pointer (16 bits): 0 (only valid if URG flag is set)
tcphdr.th_urp = htons (0);
// TCP checksum (16 bits)
tcphdr.th_sum = tcp4_checksum (iphdr, tcphdr, data, datalen);
// Fill out ethernet frame header.
// Next is ethernet frame data (IPv4 header + TCP header).
// IPv4 header
memcpy (snd_ip_frame, &iphdr, IP4_HDRLEN * sizeof (uint8_t));
// TCP header
memcpy (snd_ip_frame + IP4_HDRLEN, &tcphdr, TCP_HDRLEN * sizeof (uint8_t));
// TCP data
memcpy (snd_ip_frame + IP4_HDRLEN + TCP_HDRLEN, data, datalen * sizeof (uint8_t));
// Free allocated memory.
free (ip_flags);
free (tcp_flags);
return (EXIT_SUCCESS);
}
// Checksum function
uint16_t
checksum (uint16_t *addr, int len)
{
int nleft = len;
int sum = 0;
uint16_t *w = addr;
uint16_t answer = 0;
while (nleft > 1) {
sum += *w++;
nleft -= sizeof (uint16_t);
}
if (nleft == 1) {
*(uint8_t *) (&answer) = *(uint8_t *) w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
// Build IPv4 TCP pseudo-header and call checksum function.
uint16_t
tcp4_checksum (struct ip iphdr, struct tcphdr tcphdr, uint8_t *payload, int payloadlen)
{
uint16_t svalue;
char buf[IP_MAXPACKET], cvalue;
char *ptr;
int chksumlen = 0;
int i;
ptr = &buf[0]; // ptr points to beginning of buffer buf
// Copy source IP address into buf (32 bits)
memcpy (ptr, &iphdr.ip_src.s_addr, sizeof (iphdr.ip_src.s_addr));
ptr += sizeof (iphdr.ip_src.s_addr);
chksumlen += sizeof (iphdr.ip_src.s_addr);
// Copy destination IP address into buf (32 bits)
memcpy (ptr, &iphdr.ip_dst.s_addr, sizeof (iphdr.ip_dst.s_addr));
ptr += sizeof (iphdr.ip_dst.s_addr);
chksumlen += sizeof (iphdr.ip_dst.s_addr);
// Copy zero field to buf (8 bits)
*ptr = 0; ptr++;
chksumlen += 1;
// Copy transport layer protocol to buf (8 bits)
memcpy (ptr, &iphdr.ip_p, sizeof (iphdr.ip_p));
ptr += sizeof (iphdr.ip_p);
chksumlen += sizeof (iphdr.ip_p);
// Copy TCP length to buf (16 bits)
svalue = htons (sizeof (tcphdr) + payloadlen);
memcpy (ptr, &svalue, sizeof (svalue));
ptr += sizeof (svalue);
chksumlen += sizeof (svalue);
// Copy TCP source port to buf (16 bits)
memcpy (ptr, &tcphdr.th_sport, sizeof (tcphdr.th_sport));
ptr += sizeof (tcphdr.th_sport);
chksumlen += sizeof (tcphdr.th_sport);
// Copy TCP destination port to buf (16 bits)
memcpy (ptr, &tcphdr.th_dport, sizeof (tcphdr.th_dport));
ptr += sizeof (tcphdr.th_dport);
chksumlen += sizeof (tcphdr.th_dport);
// Copy sequence number to buf (32 bits)
memcpy (ptr, &tcphdr.th_seq, sizeof (tcphdr.th_seq));
ptr += sizeof (tcphdr.th_seq);
chksumlen += sizeof (tcphdr.th_seq);
// Copy acknowledgement number to buf (32 bits)
memcpy (ptr, &tcphdr.th_ack, sizeof (tcphdr.th_ack));
ptr += sizeof (tcphdr.th_ack);
chksumlen += sizeof (tcphdr.th_ack);
// Copy data offset to buf (4 bits) and
// copy reserved bits to buf (4 bits)
cvalue = (tcphdr.th_off << 4) + tcphdr.th_x2;
memcpy (ptr, &cvalue, sizeof (cvalue));
ptr += sizeof (cvalue);
chksumlen += sizeof (cvalue);
// Copy TCP flags to buf (8 bits)
memcpy (ptr, &tcphdr.th_flags, sizeof (tcphdr.th_flags));
ptr += sizeof (tcphdr.th_flags);
chksumlen += sizeof (tcphdr.th_flags);
// Copy TCP window size to buf (16 bits)
memcpy (ptr, &tcphdr.th_win, sizeof (tcphdr.th_win));
ptr += sizeof (tcphdr.th_win);
chksumlen += sizeof (tcphdr.th_win);
// Copy TCP checksum to buf (16 bits)
// Zero, since we don't know it yet
*ptr = 0; ptr++;
*ptr = 0; ptr++;
chksumlen += 2;
// Copy urgent pointer to buf (16 bits)
memcpy (ptr, &tcphdr.th_urp, sizeof (tcphdr.th_urp));
ptr += sizeof (tcphdr.th_urp);
chksumlen += sizeof (tcphdr.th_urp);
// Copy payload to buf
memcpy (ptr, payload, payloadlen);
ptr += payloadlen;
chksumlen += payloadlen;
// Pad to the next 16-bit boundary
for (i=0; i<payloadlen%2; i++, ptr++) {
*ptr = 0;
ptr++;
chksumlen++;
}
return checksum ((uint16_t *) buf, chksumlen);
}
// Allocate memory for an array of chars.
char *
allocate_strmem (int len)
{
void *tmp;
if (len <= 0) {
fprintf (stderr, "ERROR: Cannot allocate memory because len = %i in allocate_strmem().\n", len);
exit (EXIT_FAILURE);
}
tmp = (char *) malloc (len * sizeof (char));
if (tmp != NULL) {
memset (tmp, 0, len * sizeof (char));
return (tmp);
} else {
fprintf (stderr, "ERROR: Cannot allocate memory for array allocate_strmem().\n");
exit (EXIT_FAILURE);
}
}
// Allocate memory for an array of unsigned chars.
uint8_t *
allocate_ustrmem (int len)
{
void *tmp;
if (len <= 0) {
fprintf (stderr, "ERROR: Cannot allocate memory because len = %i in allocate_ustrmem().\n", len);
exit (EXIT_FAILURE);
}
tmp = (uint8_t *) malloc (len * sizeof (uint8_t));
if (tmp != NULL) {
memset (tmp, 0, len * sizeof (uint8_t));
return (tmp);
} else {
fprintf (stderr, "ERROR: Cannot allocate memory for array allocate_ustrmem().\n");
exit (EXIT_FAILURE);
}
}
// Allocate memory for an array of ints.
int *
allocate_intmem (int len)
{
void *tmp;
if (len <= 0) {
fprintf (stderr, "ERROR: Cannot allocate memory because len = %i in allocate_intmem().\n", len);
exit (EXIT_FAILURE);
}
tmp = (int *) malloc (len * sizeof (int));
if (tmp != NULL) {
memset (tmp, 0, len * sizeof (int));
return (tmp);
} else {
fprintf (stderr, "ERROR: Cannot allocate memory for array allocate_intmem().\n");
exit (EXIT_FAILURE);
}
}
【运行输出】