Redeemer, как-то криво ты сокет открываешь для записи сырых данных в него. Какой код ошибки возвращается 'errno'?
Если ты открываешь RAW сокет а функцию маршрутизации пакетов полностью перекладываешь на ядро, то там есть какие то тонкости, в IP_HDR по моему src-ip указывать не надо, и crc в ip-hdr то же формировать не надо. Сейчас соответствующей документации у меня нет под рукой.
Вот посмотри пример, программа читает pcap-dump и выкидывает его содержимое в интерфейс (eth0, ...). Pcap-dump можно записать 'tcpdump'-ом или 'Wireshark'-ом. Обрати внимание на функцию 'open_eth_dev', она открывает интерфейс для записи в него пакетов из pcapdump-а:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <arpa/inet.h>
#include "gentraf.h"
/**
* Формат PCAP файла имеет следующий вид:
* +-------------+-------------+-----------+-------------+-----------+---+
* |Global Header|Packet Header|Packet Data|Packet Header|Packet Data|...|
* +-------------+-------------+-----------+-------------+-----------+---+
*/
/* Pcap Global Header */
struct pcap_global_head {
uint32_t magic; /* магический номер */
uint16_t version_major; /* старший номер версии */
uint16_t version_minor; /* младший номер версии */
uint32_t thiszone; /* корекция времени GMT (временная зона) */
uint32_t sigfigs; /* временная погрешность (всегда 0) */
uint32_t snaplen; /* длина кадра */
uint32_t linktype; /* тип канального уровня (Ethernet, PPP, ...) */
};
/* Pcap Packet Header */
struct pcap_packet_head {
uint32_t tv_sec; /* время захвата пакета */
uint32_t tv_usec; /* микросекунд от tv_sec захвата пакета */
uint32_t caplen; /* колличество байт в блоке данных пакета */
uint32_t len; /* размер блока данных пакета */
};
/* Pcap Packet Data */
struct pcap_packet_data {
struct pcap_packet_head p_head; /* заголовок пакета */
unsigned char *packet_data; /* данные пакета */
};
/* Pcap Data */
struct pcap_file_data {
struct pcap_global_head p_glob_head; /* заголовок pcap файла */
int number_packet_data; /* количество пакетов */
struct pcap_packet_data *p_packets; /* массив пакетов */
};
static void help(void)
{
fprintf(stderr, "Usage: " PROGNAME " [options] file...\n"
"\n"
"Options:\n"
" -i [INTERF] writen on interface\n"
" -s [SEC] job time in seconds\n"
" -c [COUNT] cycles to send the file\n"
" -h view this help\n");
}
static void usage(void)
{
fprintf(stderr, "Usage: " PROGNAME " [options] -i [eth] file\n");
}
/*
* Возвращает количество пакетов находящихся
* в pcap файле.
*/
static int get_number_pcap_packet(FILE *fp)
{
int number;
fseek(fp, sizeof(struct pcap_global_head), SEEK_SET);
for (number = 0;;) {
struct pcap_packet_head p_packet;
size_t n;
n = fread(&p_packet, sizeof(p_packet), 1, fp);
if (n != 1) {
if (!feof(fp)) {
err_msg("Failed counting packets of pcap file.");
return 0;
} else
break;
}
number++;
fseek(fp, p_packet.caplen, SEEK_CUR);
}
return number;
}
/*
* Загружает pcap файл в память и возвращает указатель на
* структуру pcap_file_data содержащую данные из файла.
*/
static struct pcap_file_data *load_pcap_file(const char *pcap_name)
{
struct pcap_file_data *p_file = NULL;
struct pcap_global_head p_glob_head;
int number_packet_data, i;
FILE *fp;
if ((fp = fopen(pcap_name, "rb")) == NULL)
return NULL;
if (fread(&p_glob_head, sizeof(p_glob_head), 1, fp) != 1)
goto out;
#define PCAP_MAGIC 0xa1b2c3d4
#define PCAP_VERSION_MAJOR 2
#define PCAP_VERSION_MINOR 4
if (p_glob_head.magic != PCAP_MAGIC ||
p_glob_head.version_major != PCAP_VERSION_MAJOR ||
p_glob_head.version_minor != PCAP_VERSION_MINOR) {
err_msg("The '%s' no pcap format file.", pcap_name);
goto out;
}
number_packet_data = get_number_pcap_packet(fp);
if (!number_packet_data) {
err_msg("It '%s' not contain pcap data.", pcap_name);
goto out;
}
p_file = xmalloc(sizeof(*p_file));
p_file->p_glob_head = p_glob_head;
p_file->p_packets =
xmalloc(sizeof(*p_file->p_packets) * number_packet_data);
fseek(fp, sizeof(struct pcap_global_head), SEEK_SET);
for (i = 0; i < number_packet_data; i++) {
struct pcap_packet_data *p;
size_t n;
p = &p_file->p_packets[i];
n = fread(&p->p_head, sizeof(p->p_head), 1, fp);
if (n != 1) {
err_msg("Failed load packet head is '%s' pcap file.\n"
"Loading only %d packets one of a %d.",
pcap_name, i, number_packet_data);
break;
}
p->packet_data = xmalloc(p->p_head.caplen);
n = fread(p->packet_data, p->p_head.caplen, 1, fp);
if (n != 1) {
err_msg("Failed load packet data is '%s' pcap file.\n"
"Loading only %d packets one of a %d.",
pcap_name, i, number_packet_data);
break;
}
}
p_file->number_packet_data = i;
out:
fclose(fp);
return p_file;
}
/*
* Освобождает память выделенную под загруженный pcap файл.
*/
static void free_pcap_file(struct pcap_file_data *p_file)
{
int i;
for (i = 0; i < p_file->number_packet_data; i++)
xfree(p_file->p_packets[i].packet_data);
xfree(p_file->p_packets);
xfree(p_file);
}
/*
* Открывает eth интерфейс для записи в него пакетов.
*/
static int open_eth_dev(const char *eth_name)
{
int sock;
struct ifreq ifr;
struct sockaddr_ll sll;
sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock == -1) {
err_msg("Failed open RAW socket: %s", strerror(errno));
return -1;
}
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, eth_name, sizeof(ifr.ifr_name) - 1);
if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) {
err_msg("ioctl SIOCGIFINDEX error: %s", strerror(errno));
goto errout;
}
memset(&sll, 0, sizeof(sll));
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
sll.sll_protocol = htons(ETH_P_ALL);
if (bind(sock, (struct sockaddr *)&sll, sizeof(sll)) == -1) {
err_msg("Failed binding socket: %s", strerror(errno));
goto errout;
}
return sock;
errout:
close(sock);
return -1;
}
/*
* Закрывает eth интерфей.
*/
static void close_eth_dev(int sock)
{
close(sock);
}
/* флаг указывающий о прекращении работы */
static volatile int flags_exit;
static void sig_func(int signo)
{
if (signo == SIGINT)
printf("signal SIGINT\n");
flags_exit = 1;
}
int main(int argc, char **argv)
{
const char *fpcap = NULL, *dev = NULL;
struct pcap_file_data *p_file;
int oc, sock_dev;
int count_send = 0, timeout_job = 0;
prog_name = argv[0];
while ((oc = getopt(argc, argv, ":i:s:c:h")) != -1) {
switch (oc) {
case 'i':
dev = optarg;
break;
case 's':
timeout_job = atoi(optarg);
break;
case 'c':
count_send = atoi(optarg);
break;
case 'h':
help();
exit(1);
break;
case ':':
err_quit("option '-%c' requires an argument.", optopt);
break;
case '?':
default:
err_quit("option '-%c' is invalid.", optopt);
break;
}
}
fpcap = argv[optind];
if (!dev || !fpcap) {
usage();
exit(1);
}
if ((p_file = load_pcap_file(fpcap)) == NULL)
err_quit("Failed load '%s' pcap file.", fpcap);
if ((sock_dev = open_eth_dev(dev)) == -1)
err_quit("Failed open '%s' device.", dev);
if (signal(SIGALRM, sig_func) == SIG_ERR)
err_quit("Failed setting signal 'SIGALRM': %s", strerror(errno));
if (signal(SIGINT, sig_func) == SIG_ERR)
err_quit("Failed setting signal 'SIGINT': %s", strerror(errno));
if (timeout_job)
alarm(timeout_job);
while (!flags_exit) {
int i;
for (i = 0; !flags_exit && (i < p_file->number_packet_data); i++) {
struct pcap_packet_data *p = &p_file->p_packets[i];
size_t n;
n = write(sock_dev, p->packet_data, p->p_head.caplen);
if (n == -1) {
err_quit("Error writing device '%s': %s",
dev, strerror(errno));
} else if (n != p->p_head.caplen) {
err_msg("WARNING: writing %u of %u in the '%s': %s",
(unsigned)n, p->p_head.caplen, dev, strerror(errno));
}
}
if (count_send) {
if (!--count_send)
flags_exit = 1;
}
}
if (timeout_job)
alarm(0);
close_eth_dev(sock_dev);
free_pcap_file(p_file);
return 0;
}