#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#ifdef _WIN32
# include <libpcapng/win_compat.h>
#else
# include <arpa/inet.h>
#endif
#include <libpcapng/protocols/ethernet.h>
#include <libpcapng/protocols/tcp.h>
uint16_t libpcapng_tcp_checksum(const struct libpcapng_ipv4_hdr *ip, const struct tcp_hdr *tcp, const uint8_t *payload, size_t payload_len) {
uint32_t sum = 0;
uint32_t saddr = ntohl(ip->saddr);
uint32_t daddr = ntohl(ip->daddr);
sum += (saddr >> 16) & 0xffff;
sum += saddr & 0xffff;
sum += (daddr >> 16) & 0xffff;
sum += daddr & 0xffff;
sum += htons(ip->protocol);
uint16_t tcp_len = htons(sizeof(struct tcp_hdr) + payload_len);
sum += tcp_len;
const uint8_t *tcpbytes = (const uint8_t*)tcp;
for (size_t i = 0; i + 1 < sizeof(struct tcp_hdr); i += 2) {
uint16_t w = (tcpbytes[i] << 8) | tcpbytes[i+1];
sum += w;
}
for (size_t i = 0; i + 1 < payload_len; i += 2) {
uint16_t w = (payload[i] << 8) | payload[i+1];
sum += w;
}
if (payload_len & 1) {
uint16_t w = (payload[payload_len - 1] << 8);
sum += w;
}
while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
return htons(~sum & 0xffff);
}
void libpcapng_fill_tcp_header(struct tcp_hdr *tcp, uint16_t sport, uint16_t dport, uint32_t seq, uint32_t ack, uint8_t flags, uint16_t window) {
memset(tcp, 0, sizeof(*tcp));
tcp->sport = htons(sport);
tcp->dport = htons(dport);
tcp->seq = htonl(seq);
tcp->ack_seq = htonl(ack);
tcp->doff = 5; tcp->fin = (flags & 0x01) ? 1 : 0;
tcp->syn = (flags & 0x02) ? 1 : 0;
tcp->rst = (flags & 0x04) ? 1 : 0;
tcp->psh = (flags & 0x08) ? 1 : 0;
tcp->ack = (flags & 0x10) ? 1 : 0;
tcp->urg = (flags & 0x20) ? 1 : 0;
tcp->window = htons(window);
tcp->checksum = 0;
tcp->urg_ptr = 0;
}
void libpcapng_tcp_packet_build(const uint8_t src_mac[6], const uint8_t dst_mac[6],
uint32_t src_ip, uint32_t dst_ip,
uint16_t src_port, uint16_t dst_port,
uint32_t seq, uint32_t ack, uint8_t flags,
const uint8_t *payload, size_t payload_len,
uint8_t *frame_out, size_t *frame_len) {
uint8_t frame[65536];
size_t offset = 0;
struct libpcapng_eth_hdr eth;
memcpy(eth.dst, dst_mac, 6);
memcpy(eth.src, src_mac, 6);
eth.ethertype = htons(0x0800); memcpy(frame + offset, ð, sizeof(eth));
offset += sizeof(eth);
struct libpcapng_ipv4_hdr ip;
uint16_t ip_total_len = sizeof(struct libpcapng_ipv4_hdr) + sizeof(struct tcp_hdr) + payload_len;
libpcapng_fill_ipv4_header(&ip, src_ip, dst_ip, ip_total_len, IPPROTO_TCP);
memcpy(frame + offset, &ip, sizeof(ip));
offset += sizeof(ip);
struct tcp_hdr tcp;
libpcapng_fill_tcp_header(&tcp, src_port, dst_port, seq, ack, flags, 65535);
tcp.checksum = libpcapng_tcp_checksum(&ip, &tcp, payload, payload_len);
memcpy(frame + offset, &tcp, sizeof(tcp));
offset += sizeof(tcp);
if (payload_len > 0) {
memcpy(frame + offset, payload, payload_len);
offset += payload_len;
}
*frame_len = offset;
memcpy(frame_out, frame, *frame_len);
}