ここからsimpletunに似たプログラムを作っています。
アプリケーションは、UDPブロードキャストをTapインターフェイスに送信します。
タップインターフェイス(simpletunと同様)でリッスンしているプログラムは、パケットを受信し、ブロードキャストとして再度エコーします。
Wiresharkで両方のパケットを確認できますが、アプリケーションはそれを受信しません。カーネルがそれらをドロップしているようです。
同様のパケットが別のマシンから送信された場合。それはうまくいきます。
tun / tapコード:-
char datagram[4096];
struct pseudo_header
{
u_int32_t source_address;
u_int32_t dest_address;
u_int8_t placeholder;
u_int8_t protocol;
u_int16_t udp_length;
};
struct pseudo_header psh;
char *pseudogram;
nread = cread(tap_fd, buffer, BUFSIZE);
memcpy(&source_port,(char *)(buffer+14+20),2);
memset (datagram, 0, 4096);
memcpy(datagram,buffer,14); //copy eth-header
datagram[6] = 0xXX;//change mac address
datagram[7] = 0xXX;
datagram[8] = 0xXX;
//IP header
struct iphdr *iph = (struct iphdr *) (datagram +14);
//TCP header
struct udphdr *udph = (struct udphdr *) (datagram + 14 + sizeof (struct iphdr));
data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr) +14;
strcpy(data,"Any string");
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof (struct iphdr) + sizeof (struct udphdr) + strlen(data);
iph->id = htonl (54321); //Id of this packet
iph->frag_off = 0;
iph->ttl = 255;
iph->protocol = IPPROTO_UDP;
iph->check = 0; //Set to 0 before calculating checksum
strcpy(source_ip , "192.168.0.99");
iph->saddr = inet_addr ( source_ip ); //Spoof the source ip address
strcpy(destination_ip , "255.255.255.255");
iph->daddr = inet_addr (destination_ip);
udph->source = htons(5933);
//udph->dest = htons(source_port);
udph->dest = (source_port);
udph->len = htons(sizeof(struct udphdr) + strlen(data));
//Now the UDP checksum
psh.source_address = inet_addr( source_ip );
psh.dest_address = inet_addr(destination_ip);
psh.placeholder = 0;
psh.protocol = IPPROTO_UDP;
psh.udp_length = htons(sizeof(struct udphdr) + strlen(data) );
int psize = sizeof(struct pseudo_header) + sizeof(struct udphdr) + strlen(data);
pseudogram = malloc(psize);
memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header) , udph , sizeof(struct udphdr) + strlen(data));
memcpy(pseudogram + sizeof(struct pseudo_header) + sizeof(struct udphdr), data , strlen(data));
udph->check = 0;
udph->check = csum( (unsigned short*) pseudogram , psize);
//Ip checksum
iph->check = csum ((unsigned short *) datagram, iph->tot_len);
//writeback
cwrite(tap_fd,datagram,iph->tot_len +14);
上記のコードは、rawソケットの読み取りと書き込みを使用して別のマシンから実行すると、うまく機能します。(ethヘッダーなし)。
アプリケーションコードの受信:-
int broadcast =1;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
err("socket");
setsockopt(sockfd,SOL_SOCKET,SO_BINDTODEVICE,"tun0",5);
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(PORT);
memset(&my_addr.sin_addr.s_addr,255,sizeof(my_addr.sin_addr.s_addr));
ret = setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&broadcast,sizeof(broadcast));
if(ret<0)
printf("setsockopt bindto failed");
if (sendto(sockfd,buf,500,0, (struct sockaddr*)&my_addr,slen_len) == -1)
err("send()");
recvfrom(sockfd, buf, 500, 0, (struct sockaddr*)&cli_addr, &slen);