我编写了一个微型测试程序,以便通过原始套接字发送自己的数据包。
我想从头开始创建数据包。
目标操作系统是FreeBSD / Mac OSX x86_64。
我的编译器是带有Apple LLVM 10的gcc。
我使用sudo权限运行该程序。
由于某种原因,sendto()总是返回“无效参数”错误,我不知道为什么。我很想解决这个问题。
我设置IP_HDRINCL
标志并通过bind
调用绑定到特定的网络接口。但是,sendto似乎并不满意它作为数据包接收到的内容。
无论如何,这是到目前为止我的代码的样子:
#include <stdio.h>
#include <stdlib.h> // EXIT_FAILURE EXIT_SUCCESS
#include <stdbool.h> // bool
#include <string.h> // strlen(), memcpy()
#include <sys/socket.h> // socket()
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h> // IPPROTO_TCP
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/if_ether.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <net/if_dl.h>
#include <ifaddrs.h>
#include <net/ethernet.h>
#include <netinet/udp.h>
#define DESTMAC "ed:5b:b6:29:43:d5"
#define DESTIP "192.168.178.25"
#define DESTPORT 23452
#define SRCPORT 23451
#define PKT_SIZ 64
#ifndef AF_PACKET
# ifdef PF_LINK
# define AF_PACKET PF_LINK
# elif defined (AF_LINK)
# define AF_PACKET AF_LINK
# endif
#endif
typedef int in_socket_t;
uint16_t udp_checksum(struct udphdr *p_udp_header, size_t len, uint32_t src_addr, uint32_t dest_addr)
{
const uint16_t *buf = (const uint16_t*)p_udp_header;
uint16_t *ip_src = (void*)&src_addr, *ip_dst = (void*)&dest_addr;
uint32_t sum;
size_t length = len;
// Calculate the sum
sum = 0;
while (len > 1)
{
sum += *buf++;
if (sum & 0x80000000)
sum = (sum & 0xFFFF) + (sum >> 16);
len -= 2;
}
if (len & 1)
// Add the padding if the packet lenght is odd
sum += *((uint8_t*)buf);
// Add the pseudo-header
sum += *(ip_src++);
sum += *ip_src;
sum += *(ip_dst++);
sum += *ip_dst;
sum += htons(IPPROTO_UDP);
sum += htons(length);
// Add the carries
while (sum >> 16)
sum = (sum & 0xFFFF) + (sum >> 16);
// Return the one's complement of sum
return (uint16_t)~sum;
}
unsigned short checksum(unsigned short *buf, int _16bitword)
{
unsigned long sum;
for (sum = 0; _16bitword > 0; _16bitword--)
sum += htons(*(buf)++);
sum = ((sum >> 16) + (sum & 0xFFFF));
sum += (sum >> 16);
return (unsigned short)~sum;
}
int main(int argc, const char **argv)
{
in_socket_t sock_r;
struct ifreq ifreq_i = { 0 }, ifreq_c = { 0 }, ifreq_ip = { 0 };
unsigned char *packet = NULL;
struct ether_header *eth = NULL;
struct ifaddrs *ifaddr = NULL;
unsigned int if_c = 0, pckt_len = 0;
struct ether_addr *eth_daddr;
ssize_t send_len;
const int on_f = 1;
if ((packet = (unsigned char *) malloc(PKT_SIZ)) == NULL)
{
perror("Could not allocate packet memory");
exit(EXIT_FAILURE);
}
memset(packet, 0, PKT_SIZ);
/// 1. Ethernet Header Construction
puts("PHASE 1: Ethernet Header Construction");
eth = (struct ether_header *)packet;
if ((sock_r = socket(PF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
{
perror("Could not create socket");
exit(EXIT_FAILURE);
}
if (setsockopt(sock_r, IPPROTO_IP, IP_HDRINCL, &on_f, sizeof(on_f)) == -1)
{
perror("Could not request manually including header within data");
exit(EXIT_FAILURE);
}
// Get IF Index
strncpy(ifreq_i.ifr_name, "en7", IFNAMSIZ - 1);
#if !defined(SIOCGIFNAME)
if (!(ifreq_i.ifr_intval = if_nametoindex(ifreq_i.ifr_name)))
{
fprintf(stderr, "Could not get interface name for interface %s: %s\n", ifreq_i.ifr_name, strerror(errno));
exit(EXIT_FAILURE);
}
#else
#error "Not yet implemented."
#endif
// Get IF MAC Address.
strncpy(ifreq_c.ifr_name, ifreq_i.ifr_name, IFNAMSIZ - 1);
#ifndef SIOCGIFHWADDR
if (getifaddrs(&ifaddr) == -1)
{
perror("Could not get interface address");
exit(EXIT_FAILURE);
}
for (; ifaddr->ifa_next; ifaddr = ifaddr->ifa_next, if_c++)
{
if (!strcmp(ifaddr->ifa_name, ifreq_c.ifr_name) && ifaddr->ifa_addr && ifaddr->ifa_addr->sa_family == AF_PACKET)
{
// Copy the Source (local) NIC MAC address to the packet (ethernet header). It's already in network format.
memcpy(eth->ether_shost, (unsigned char *) LLADDR((struct sockaddr_dl *) ifaddr->ifa_addr), ETHER_ADDR_LEN);
}
}
freeifaddrs(ifaddr - if_c);
#elif defined(SIOCGIFHWADDR)
if (ioctl(sock_r, SIOCGIFHWADDR, &ifreq_c) == -1)
{
fprintf(stderr, "Could not get MAC address for interface %s: %s\n", ifreq_c.ifr_name, strerror(errno));
exit(EXIT_FAILURE);
}
#else
#error "Not yet implemented."
#endif
// Get IF assigned IP Address.
strncpy(ifreq_ip.ifr_name, ifreq_c.ifr_name, IFNAMSIZ - 1);
#if defined(SIOCGIFADDR)
if (ioctl(sock_r, SIOCGIFADDR, &ifreq_ip) == -1)
{
fprintf(stderr, "Could not get IP address for interface %s: %s\n", ifreq_ip.ifr_name, strerror(errno));
exit(EXIT_FAILURE);
}
#else
#error "Not yet implemented."
#endif
// Copy the destination NIC MAC address to the packet (ethernet header).
// ether_aton converts a human-readable NIC MAC to network format.
// TODO: Remember that we don't want to have a fixed destination NIC MAC, we'll probably receive it with an ARP request in the future.
if ((eth_daddr = ether_aton(DESTMAC)) == NULL)
{
perror("Could not convert destination NIC MAC address to network format");
exit(EXIT_FAILURE);
}
memcpy(eth->ether_dhost, eth_daddr->octet, ETHER_ADDR_LEN);
eth->ether_type = htons(ETHERTYPE_IP);
// Calculate total packet length.
pckt_len += sizeof(*eth);
printf("Source Host: %s\n", ether_ntoa((const struct ether_addr *)eth->ether_shost));
printf("Desti. Host: %s\n", ether_ntoa((const struct ether_addr *)eth->ether_dhost));
printf("Ether. Type: 0x%0x%s\n", ntohs(eth->ether_type), ntohs(eth->ether_type) == 0x800 ? " (IP)" : "");
if (bind(sock_r, (struct sockaddr *)ifaddr->ifa_addr, sizeof(struct sockaddr)) == -1)
{
perror("Could not bind to specific interface");
exit(EXIT_FAILURE);
}
/// 2. IP Header Construction
puts("\nPHASE 2: IP Header Construction");
struct ip *iph = (struct ip *)(packet + pckt_len);
// printf("IP Header %p (eth hdr siz: %i) begins at %p.\n", packet, pckt_len, packet + pckt_len);
iph->ip_hl = sizeof(struct ip) >> 2;
iph->ip_v = IPVERSION; // 4
iph->ip_tos = 16;
iph->ip_id = htons(10201); // any unique ID.
iph->ip_ttl = 64;
iph->ip_p = IPPROTO_UDP; // UDP (User datagram protocol)
iph->ip_src.s_addr = ((struct sockaddr_in *)&ifreq_ip.ifr_ifru.ifru_addr)->sin_addr.s_addr;
if (!inet_aton(DESTIP, &iph->ip_dst))
{
perror("Could not interpret destination IP address");
exit(EXIT_FAILURE);
}
// Calculate total packet length.
pckt_len += sizeof(*iph);
printf("Header length: %i\n", iph->ip_hl);
printf("Version : %i%s\n", iph->ip_v, iph->ip_v == IPVERSION ? " (IPv4)" : "");
printf("Type of Serv.: %i\n", iph->ip_tos);
printf("Identificati.: %i\n", ntohs(iph->ip_id));
printf("Time to live : %i\n", iph->ip_ttl);
printf("Protocol : %i%s\n", iph->ip_p, iph->ip_p == IPPROTO_UDP ? " (UDP)" : "");
printf("Source Addre.: %s%s\n", inet_ntoa(iph->ip_src), " (local IP)");
printf("Dest. Address: %s\n", inet_ntoa(iph->ip_dst));
/// 3. UDP Header Construction
struct udphdr *udph = (struct udphdr *)(packet + pckt_len);
udph->uh_sport = htons(SRCPORT);
udph->uh_dport = htons(DESTPORT);
udph->uh_sum = 0;
// Calculate total packet length.
pckt_len += sizeof(*udph);
// Actual UDP Payload:
packet[pckt_len++] = 0xAA;
packet[pckt_len++] = 0xBB;
packet[pckt_len++] = 0xCC;
packet[pckt_len++] = 0xDD;
packet[pckt_len++] = 0xEE;
// Fill out remaining length header fields:
// UDP length field
udph->uh_ulen = htons(pckt_len - sizeof(*iph) - sizeof(*eth));
// IP length field
iph->ip_len = htons(pckt_len - sizeof(*eth));
// Finally, calculate the checksum.
iph->ip_sum = checksum((unsigned short *)(packet + sizeof(*eth)), sizeof(*iph) / 2);
udph->uh_sum = udp_checksum(udph, pckt_len, iph->ip_src.s_addr, iph->ip_dst.s_addr);
struct sockaddr_dl saddr_dl = { 0 };
memset(&saddr_dl, 0, sizeof(struct sockaddr_dl));
saddr_dl.sdl_index = ifreq_i.ifr_intval;
saddr_dl.sdl_family = AF_LINK;
saddr_dl.sdl_type = IFRTYPE_FUNCTIONAL_WIRED; // APPLE_IF_FAM_ETHERNET
saddr_dl.sdl_nlen = strlen(ifreq_i.ifr_name);
saddr_dl.sdl_len = sizeof(struct sockaddr_dl);
saddr_dl.sdl_alen = ETHER_ADDR_LEN;
memcpy(saddr_dl.sdl_data, eth_daddr->octet, ETHER_ADDR_LEN);
puts("\nPHASE 4: SENDING PACKET");
printf("Packet length: %i\n", pckt_len);
printf("Interface index: %i; %i\n", saddr_dl.sdl_index, ifreq_i.ifr_intval);
// Send the packet.
if ((send_len = sendto(sock_r, packet, PKT_SIZ, 0, (const struct sockaddr *)&saddr_dl, sizeof(saddr_dl))) == -1)
{
perror("Could not send packet");
exit(EXIT_FAILURE);
}
printf("Successfully sent packet with data length: %lu\n", send_len);
return 0;
}
不用担心错误检查,由于这段代码已经很大,所以我省去了。
这是结果之一:
PHASE 1: Ethernet Header Construction
Source Host: 5E:F1:28:36:5E:DB
Desti. Host: ED:5B:B6:29:43:D5
Ether. Type: 0x800
PHASE 2: IP Header Construction
IP Header 0x5fcde63019a0 (eth hdr siz: 14) begins at 0x5fcde63019ae.
Header length: 5
Version : 4 (IPv4)
Type of Serv.: 16
Identificati.: 10201
Time to live : 68
Protocol : 17 (UDP)
Source Addre.: 192.168.178.21 (local IP)
Dest. Address: 192.168.178.25
PHASE 4: SENDING PACKET
Interface Index: 7
Packet length: 47
Destination mac: ed:5b:b6:29:43:d5
Could not send packet: Invalid argument
我正在将sockaddr_dl结构转换为sockaddr。它们都在其头文件中定义,如下所示:
struct sockaddr {
__uint8_t sa_len; /* total length */
sa_family_t sa_family; /* [XSI] address family */
char sa_data[14]; /* [XSI] addr value (actually larger) */
};
struct sockaddr_dl {
u_char sdl_len; /* Total length of sockaddr */
u_char sdl_family; /* AF_LINK */
u_short sdl_index; /* if != 0, system given index for interface */
u_char sdl_type; /* interface type */
u_char sdl_nlen; /* interface name length, no trailing 0 reqd. */
u_char sdl_alen; /* link level address length */
u_char sdl_slen; /* link layer selector length */
char sdl_data[12]; /* minimum work area, can be larger;
contains both if name and ll address */
};
答案 0 :(得分:1)
socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
使您可以访问IP级别。要访问以太网级别,在Linux中,您需要使用PF_PACKET
并获得类型为socket(PF_PACKET, SOCK_RAW, SOCK_DATAGRAM);
的套接字。
恐怕您是在IP数据报的顶部格式化以太网数据包。有关此类套接字的文档,请参见 packet(7)。
此外,检查每个系统调用中的错误绝对是一个好主意。这可能是您了解底层情况的好方法。
此外,如果您向您发送数据包(目标以太网地址与源以太网地址相同),您将永远无法将数据包退还给您。在发送此类数据包之前,软件应检测到目标地址和源地址相同。由于所有系统都试图不占用带宽,因此通常以太网卡会广播您的数据包。但是,没有太多的以太网在发送数据包时侦听以太网。您可以通过这种行为来欺骗自己,但那是做事的常见方式(不要发送指向您的数据包)。
最可能导致EINVAL
错误的原因可能是您将-1
作为套接字参数,只是因为您假设您的socket(2)
调用正常,但是没有成功t,您认为您不需要在那里检查错误。但是,您正在格式化IP pdu的有效负载中的以太网数据包。有很多事情可能会出错。您传递给套接字接口的sockaddr
可能无效,长度错误,内部格式错误。所有这些都脱离了无效的协议系列,这使您收到错误的套接字类型,甚至更糟的是错误。
另一件事:不要犹豫发布complete (with all the headers you used) and out of the box verifiable example。这是必须遵循的。您可能使用了错误的头文件,并且可能是来源或错误,但我们不知道是否在发布前将其剪切了。如果甚至添加用于构建示例的Makefile
,也会更好。这样没人会说好吧,我尝试了您的示例代码,但它甚至没有编译。您可以将工作保存给我们所有人,这些工作必须首先将您的代码修复为某种可用的代码,可能会以这种方式纠正您的错误。您在解释中假设自己做对了所有事情,因此您认为不需要发布无用的数据(例如头文件等),并且在错误之上添加了错误,从而完全不可能调试代码。
答案 1 :(得分:1)
在计算校验和有问题之后,我终于找到了使用Berkeley Packet Filters的解决方案。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/if_ether.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <net/if_dl.h>
#include <ifaddrs.h>
#include <net/ethernet.h>
#include <net/bpf.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <netinet/udp.h>
#define INTERFACE "en0"
#define DESTMAC "ED:5B:B6:29:43:D5"
#define SRCMAC "5E:F1:28:36:5E:DB"
#define DESTIP "192.168.178.27"
#define DESTPORT 23455
#define SRCPORT 23456
uint32_t crc32(const void *m, size_t len)
{
const unsigned char *message = m;
size_t i;
int j;
unsigned int byte, crc, mask;
i = 0;
crc = 0xFFFFFFFF;
while (i < len) {
byte = message[i]; // Get next byte.
crc = crc ^ byte;
for (j = 7; j >= 0; j--) { // Do eight times.
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
i = i + 1;
}
return ~crc;
}
uint32_t eth_cks(const void *data, size_t frame_len)
{
if (data == NULL) return 0;
const unsigned char * const eth_frame = data;
char str[(frame_len - 4) * 2 + 1]; // +1 for null terminator.
memset(str, 0, (frame_len - 4) * 2 + 1);
for (int i = 0; i < (frame_len - 4) * 2; i += 2)
sprintf(&str[i], "%02x", eth_frame[i / 2]);
size_t len = strlen(str), len2 = (len + 1) / 2;
unsigned char arr2[len2];
for (size_t i = 0; i < len; i += 2)
arr2[i / 2] = strtoul((char[3]) {str[i], str[i + 1], '\0'}, 0, 16);
return crc32(arr2, len2);
}
uint16_t ip4_cks(const void *vdata, size_t length)
{
// Cast the data pointer to one that can be indexed.
char* data = (char *)vdata;
// Initialise the accumulator.
uint64_t acc = 0xffff;
// Handle any partial block at the start of the data.
unsigned int offset = ((uintptr_t)data)&3;
if (offset)
{
size_t count = 4 - offset;
if (count > length) count = length;
uint32_t word = 0;
memcpy(offset + (char *)&word, data, count);
acc += ntohl(word);
data += count;
length -= count;
}
// Handle any complete 32-bit blocks.
char* data_end = data + (length &~3);
while (data != data_end)
{
uint32_t word;
memcpy(&word, data, 4);
acc += ntohl(word);
data += 4;
}
length &= 3;
// Handle any partial block at the end of the data.
if (length)
{
uint32_t word = 0;
memcpy(&word, data, length);
acc += ntohl(word);
}
// Handle deferred carries.
acc = (acc & 0xffffffff) + (acc >> 32);
while (acc >> 16)
acc = (acc & 0xffff) + (acc >> 16);
// If the data began at an odd byte address
// then reverse the byte order to compensate.
if (offset&1)
acc = ((acc & 0xff00) >> 8) | ((acc & 0x00ff) << 8);
// Return the checksum in network byte order.
return htons(~acc);
}
uint16_t udp_cks(struct udphdr *p_udp_header, size_t len, uint32_t src_addr, uint32_t dest_addr)
{
const uint16_t *buf = (const uint16_t *)p_udp_header;
uint16_t *ip_src = (void *)&src_addr, *ip_dst = (void *)&dest_addr;
uint32_t sum;
size_t length = len;
// Calculate the sum
sum = 0;
while (len > 1)
{
sum += *buf++;
if (sum & 0x80000000)
sum = (sum & 0xFFFF) + (sum >> 16);
len -= 2;
}
if (len & 1)
// Add the padding if the packet lenght is odd
sum += *((uint8_t*)buf);
// Add the pseudo-header
sum += *(ip_src++);
sum += *ip_src;
sum += *(ip_dst++);
sum += *ip_dst;
sum += htons(IPPROTO_UDP);
sum += htons(length);
// Add the carries
while (sum >> 16)
sum = (sum & 0xFFFF) + (sum >> 16);
// Return the one's complement of sum
return (uint16_t)~sum;
}
int main(int argc, char **argv)
{
int bpf_f = 0;
struct ifreq ifreq_ip = { {0} }, ifreq_bpf = { {0} };
unsigned char *packet;
struct ether_header *eth;
struct ifaddrs *ifaddr = NULL;
unsigned int pckt_len = 0, if_c = 0;
uint32_t *fcs;
if (!(packet = malloc(PKT_SIZ)))
{
perror("Could not allocate memory for packet");
exit(EXIT_FAILURE);
}
memset(packet, 0, PKT_SIZ);
fcs = (uint32_t *)(packet + PKT_SIZ - SIZEOF_UINT32_T);
我们现在搜索同时可用可读和可写的可用 bpf 设备。
char buf[11] = { 0 };
for (int ext = 1; ext < 99; ++ext)
{
sprintf(buf, "/dev/bpf%i", ext);
if ((bpf_f = open(buf, O_RDWR)) != -1)
break;
}
if (!bpf_f)
{
fprintf(stderr, "Could not open BPF device.\n");
exit(EXIT_FAILURE);
}
// Bind BPF to physical device.
// Copy the interface name to the request.
strcpy(ifreq_bpf.ifr_name, ifaddr->ifa_name);
if (ioctl(bpf_f, BIOCSETIF, &ifreq_bpf) == -1)
{
perror("Could not bind BPF to physical device");
exit(EXIT_FAILURE);
}
现在,还可以禁用源MAC地址的自动报头完成。为此,请查看 bpf 的 IOCTL (尤其是BIOCGHDRCMPLT
,它是 set 的对应对象)。
eth = (struct ether_header *)packet;
// Copy the Source (local) NIC MAC address to the packet (ethernet header). It's already in network format.
memcpy(eth->ether_shost, ether_aton(SRCMAC)->octet, ETHER_ADDR_LEN);
// Copy the destination NIC MAC address to the packet (ethernet header).
// ether_aton converts a human-readable NIC MAC to network format.
当时,这仅适用于本地地址。我们不检查指定的IP地址是否是子网的一部分。
memcpy(eth->ether_dhost, ether_aton(DESTMAC)->octet, ETHER_ADDR_LEN);
// Specifiy the ethernet overlaying type.
eth->ether_type = htons(ETHERTYPE_IP);
printf("Source MAC: %s\n", ether_ntoa((const struct ether_addr *)eth->ether_shost));
printf("Desti. MAC: %s\n", ether_ntoa((const struct ether_addr *)eth->ether_dhost));
printf("Eth Type: 0x%x%s\n", ntohs(eth->ether_type), ntohs(eth->ether_type) == ETHERTYPE_IP ? " (IP)" : "");
// Get IF assigned IP address.
strncpy(ifreq_ip.ifr_name, ifreq_bpf.ifr_name, IFNAMSIZ - 1);
in_socket_t sock;
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("Could not create socket");
exit(EXIT_FAILURE);
}
#if defined(SIOCGIFADDR)
if (ioctl(sock, SIOCGIFADDR, &ifreq_ip) == -1)
{
fprintf(stderr, "Could not get IP address for interface %s: %s\n", ifreq_ip.ifr_name, strerror(errno));
}
#else
#error "Not yet implemented"
#endif
close(sock);
pckt_len += sizeof(*eth);
struct ip *iph = (struct ip *)(packet + pckt_len);
iph->ip_hl = sizeof(struct ip) >> 2;
iph->ip_v = IPVERSION; // 4
iph->ip_tos = 16;
iph->ip_id = htons(10201); // any unique ID.
iph->ip_ttl = 64;
iph->ip_p = IPPROTO_UDP; // UDP (User datagram protocol)
iph->ip_src.s_addr = ((struct sockaddr_in *)&ifreq_ip.ifr_ifru.ifru_addr)->sin_addr.s_addr;
if (!inet_aton(DESTIP, &iph->ip_dst))
{
perror("Could not interpret destination IP address");
exit(EXIT_FAILURE);
}
// Calculate total packet length.
pckt_len += sizeof(*iph);
printf("Header length: %i\n", iph->ip_hl);
printf("Version : %i%s\n", iph->ip_v, iph->ip_v == IPVERSION ? " (IPv4)" : "");
printf("Type of Serv.: %i\n", iph->ip_tos);
printf("Identificati.: %i\n", ntohs(iph->ip_id));
printf("Time to live : %i\n", iph->ip_ttl);
printf("Protocol : %i%s\n", iph->ip_p, iph->ip_p == IPPROTO_UDP ? " (UDP)" : "");
printf("Source Addre.: %s%s\n", inet_ntoa(iph->ip_src), " (local IP)");
printf("Dest. Address: %s\n", inet_ntoa(iph->ip_dst));
struct udphdr *udph = (struct udphdr *)(packet + pckt_len);
udph->uh_sport = htons(SRCPORT);
udph->uh_dport = htons(DESTPORT);
udph->uh_sum = 0;
// Calculate total packet length.
pckt_len += sizeof(*udph);
// Actual UDP Payload:
packet[pckt_len++] = 0xAA;
packet[pckt_len++] = 0xBB;
packet[pckt_len++] = 0xCC;
packet[pckt_len++] = 0xDD;
packet[pckt_len++] = 0xEE;
// Fill out remaining length header fields:
// UDP length field
udph->uh_ulen = htons(pckt_len - sizeof(*iph) - sizeof(*eth));
// IP length field
iph->ip_len = htons(pckt_len - sizeof(*eth));
// Finally, calculate the checksum.
iph->ip_sum = ip4_cks(packet + sizeof(*eth), sizeof(*iph));
udph->uh_sum = udp_cks(udph, ntohs(udph->uh_ulen), iph->ip_src.s_addr, iph->ip_dst.s_addr);
*fcs = eth_cks(packet, PKT_SIZ);
if (write(bpf_f, packet, PKT_SIZ) == -1)
{
perror("Could not write to bpf");
exit(EXIT_FAILURE);
}
free(packet);
packet = NULL;
close(bpf_f);
return 0;
}