#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/udp.h>
static uint16_t libpcapng_udp_checksum(const struct libpcapng_ipv4_hdr *ip,
const struct libpcapng_udp_hdr *udp,
const uint8_t *payload,
size_t payload_len)
{
uint32_t sum = 0;
sum += (ip->saddr >> 16) & 0xFFFF;
sum += (ip->saddr) & 0xFFFF;
sum += (ip->daddr >> 16) & 0xFFFF;
sum += (ip->daddr) & 0xFFFF;
sum += htons(IPPROTO_UDP);
sum += udp->len;
const uint8_t *u8 = (const uint8_t *)udp;
for (size_t i = 0; i < sizeof(*udp); i += 2) {
uint16_t word;
memcpy(&word, u8 + i, 2);
sum += ntohs(word);
}
const uint8_t *ptr = payload;
while (payload_len >= 2) {
sum += (ptr[0] << 8) | ptr[1];
ptr += 2;
payload_len -= 2;
}
if (payload_len == 1) {
sum += (ptr[0] << 8);
}
while (sum >> 16)
sum = (sum & 0xFFFF) + (sum >> 16);
uint16_t checksum = ~sum;
if (checksum == 0) checksum = 0xFFFF;
return htons(checksum);
}
void libpcapng_fill_udp_header(struct libpcapng_udp_hdr *udp,
uint16_t sport,
uint16_t dport,
uint16_t length)
{
memset(udp, 0, sizeof(*udp));
udp->sport = htons(sport);
udp->dport = htons(dport);
udp->len = htons(length);
udp->checksum = 0;
}
void libpcapng_udp_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,
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 udp_len = sizeof(struct libpcapng_udp_hdr) + payload_len;
uint16_t ip_total_len = sizeof(struct libpcapng_ipv4_hdr) + udp_len;
libpcapng_fill_ipv4_header(&ip, src_ip, dst_ip, ip_total_len, IPPROTO_UDP);
memcpy(frame + offset, &ip, sizeof(ip));
offset += sizeof(ip);
struct libpcapng_udp_hdr udp;
libpcapng_fill_udp_header(&udp, src_port, dst_port, udp_len);
udp.checksum = libpcapng_udp_checksum(&ip, &udp, payload, payload_len);
memcpy(frame + offset, &udp, sizeof(udp));
offset += sizeof(udp);
if (payload_len > 0) {
memcpy(frame + offset, payload, payload_len);
offset += payload_len;
}
*frame_len = offset;
memcpy(frame_out, frame, *frame_len);
}