У меня тоже такая проблема была. Я сильно не разбирался но если правильно составить ip заголовок то всё должно заработать видимо ядро его проверяет.
Для примера:
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in_systm.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#define PORT 40
int send_packet(int sock_, struct sockaddr_in sin_, char *buff_);
u_short checksum(u_short *addr, int len);
int main(int argc, char *argv[])
{
int i, sock, on = 1;
struct sockaddr_in sin;
struct _pseudoheader {
struct in_addr src_addr;
struct in_addr dst_addr;
u_char zero;
u_char protocol;
u_char length;
} pseudoheader;
struct in_addr src, dst;
struct ip *iph;
struct tcphdr *tcp;
u_char *buf = (char *)malloc(sizeof(struct ip) + sizeof(struct tcphdr));
u_char *pseudo = (char *)malloc(sizeof(struct _pseudoheader) +
sizeof(struct tcphdr));
if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
printf("socket\n");
exit(1);
}
if (setsockopt(sock, 0, 2, &on, sizeof(on)) < 0) {
printf("setsockopt\n");
exit(1);
}
iph = (struct ip *)buf;
tcp = (struct tcphdr *)(buf + sizeof(struct ip));
inet_aton("10.16.17.23",&src);
inet_aton("10.16.17.1",&dst);
pseudoheader.src_addr = src;
pseudoheader.dst_addr = dst;
pseudoheader.zero = 0;
pseudoheader.protocol = IPPROTO_TCP;
pseudoheader.length = htons(sizeof(struct tcphdr));
memcpy(pseudo,&pseudoheader,sizeof(struct _pseudoheader));
memcpy(pseudo + sizeof(struct _pseudoheader),buf + sizeof(struct ip),
sizeof(struct tcphdr));
iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = ntohs(sizeof(struct ip) + sizeof(struct tcphdr));
iph->ip_id = rand();
iph->ip_off = htons(IP_DF);
iph->ip_ttl = 64;
iph->ip_p = IPPROTO_TCP;
iph->ip_sum = 0;
iph->ip_src = src;
iph->ip_dst = dst;
tcp->th_sport = htons(rand());
tcp->th_dport = htons(PORT);
tcp->th_seq = ntohl(rand());
tcp->th_ack = rand();
tcp->th_off = 5;
tcp->th_flags = TH_SYN;
tcp->th_win = htons(512);
tcp->th_sum = checksum((u_short *)pseudo,sizeof(struct _pseudoheader) +
sizeof(struct tcphdr));
tcp->th_urp = 0;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr = dst;
send_packet(sock,sin,buf);
free(buf);
free(pseudo);
return 0;
}
int send_packet(int sock_, struct sockaddr_in sin_, char *buff_)
{
int err;
if((err = sendto(sock_, buff_, (size_t)(sizeof(struct ip) +
sizeof(struct tcphdr)), 0, (struct sockaddr *)&sin_, sizeof(sin_))) < 0) {
printf("sendto %d\n",err);
}
printf("packet send...\n");
return err;
}
u_short checksum(u_short *addr, int len)
{
u_short *w = addr;
int i = len;
int sum = 0;
u_short answer;
while(i > 0) {
sum += *w++;
i -= 2;
}
if(i == 1) sum += *(u_char *)w;
sum = (sum >> 16) + (sum & 0xffff);
sum = sum + (sum >> 16);
return (~sum);
}
Код я писал в OpenBSD.