Reputation: 329
I'm trying to add a new Hop by Hop option by using raw sockets. Since, the kernel does not process unrecognised option types, it send an ICMP error of parameter not recognized.
I tried to change a few things in the kernel by adding my new option as a known one, so the kernel does not send me the error. That is successful so far...but the problem is, that the receiver does not receive the packet. Using Wireshark it shows that the packet is intercepted at the interface, but does not show up in the user-space.
My code is as follows,
At the sender it does print "data sent" at the end, but the receiver does not print anything.
server.c
#include <sys/socket.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/ip6.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <time.h>
#define DEST "::1"
#define IPV6_TLV_OPTX 0xEE
#define IPV6_TLV_ROUTERALERT 5
short unsigned sequence_number();
short unsigned number;
int main(void)
{
int j=0, pton_fd;
int i=0;
struct ip6_hbh hbh_hdr;
struct msghdr msg = {};
struct cmsghdr *cmsg;
int cmsglen;
char src_ip[INET6_ADDRSTRLEN], dst_ip[INET6_ADDRSTRLEN];
int s,status;
struct sockaddr_in6 daddr;
char packet[40];
//-----members for ancillary data-----------
struct iovec iov[2];
void *extbuf;
socklen_t extlen;
int currentlen;
void *databuf;
int offset;
uint8_t value;
uint8_t value1;
uint8_t value2;
/* point the iphdr to the beginning of the packet */
struct ip6_hdr *ip = (struct ip6_hdr *)packet;
if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}
int setsock_offset = 2;
if(setsockopt(s, IPPROTO_IPV6, IPV6_CHECKSUM, &setsock_offset, sizeof(setsock_offset) < 0))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
daddr.sin6_family = AF_INET6;
daddr.sin6_port = 0; /* not needed in SOCK_RAW */
daddr.sin6_scope_id = if_nametoindex("eth0");
pton_fd = inet_pton(AF_INET6, "fe80::a00:27ff:fe30:9ae9", (struct in6_addr *)&daddr.sin6_addr.s6_addr);
if (pton_fd == 0)
{
printf("Does not contain a character string representing a network address");
exit(EXIT_FAILURE);
}
else if (pton_fd < 0)
{
perror("pton()");
exit(EXIT_FAILURE);
}
ip->ip6_flow = htonl ((6<<28) | (0<<20) | 0);
ip->ip6_plen = htons (8);
ip->ip6_nxt = 0;
ip->ip6_hops = 64;
if ((status = inet_pton(AF_INET6, "fe80::921b:eff:fe03:637d", &(ip->ip6_src))) != 1)
{
fprintf(stderr,"inet_pton() failed.\nError message: %s",strerror(status)); exit(EXIT_FAILURE);
}
if ((status = inet_pton(AF_INET6, "fe80::a00:27ff:fe30:9ae9", &(ip->ip6_dst))) != 1)
{
fprintf(stderr,"inet_pton() failed.\nError message: %s",strerror(status)); exit(EXIT_FAILURE);
}
// Specifying the ancillary data for Hop-by-Hop headers
currentlen = inet6_opt_init(NULL,0);
if (currentlen == -1){
perror("1st opt_init");
exit(EXIT_FAILURE);
}
printf("Hop by Hop length: %d\n", currentlen);
// Setting Hop by Hop extension header next field
//hbh_hdr.ip6h_nxt = 59;
//hbh_hdr.ip6h_len = 0;
currentlen = inet6_opt_append(NULL, 0, currentlen, IPV6_TLV_ROUTERALERT, 2, 1, NULL);
if (currentlen == -1) {
printf("ERROR NO: %d\n",errno);
//perror("1st opt_append");
fprintf(stderr, "append error %s, %s\n",strerror(errno),strerror(currentlen));
exit(EXIT_FAILURE);
}
currentlen = inet6_opt_finish(NULL, 0, currentlen);
if (currentlen == -1) {
perror("1st opt_finish");
exit(EXIT_FAILURE);
}
printf("currentlen: %d\n",currentlen);
extlen = currentlen;
cmsglen = CMSG_SPACE(extlen);
cmsg = malloc(sizeof(cmsglen));
if (cmsg == NULL) {
perror("msg malloc");
exit(EXIT_FAILURE);
}
cmsg->cmsg_len = CMSG_LEN(extlen);
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_HOPOPTS;
extbuf = CMSG_DATA(cmsg);
extbuf = malloc(extlen);
printf("Size of extbuf: %ld",sizeof(extbuf));
if (extbuf == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
printf("Extenlen: %d\n",extlen);
//hbh_hdr.ip6h_nxt = 59;
currentlen = inet6_opt_init(extbuf, extlen);
if (currentlen == -1) {
perror("2nd opt_init");
exit(EXIT_FAILURE);
}
//extbuf = (unsigned char*)extbuf;
//char ip6hop_nexth_value = 59;
*(unsigned char*)(extbuf) = 59;
unsigned char* temp = extbuf;
//for(i=0; i<extlen;i++) {
// printf("Ext buffer is: %d\n",*temp);
// temp++;
//}
currentlen = inet6_opt_append(extbuf, extlen, currentlen, IPV6_TLV_ROUTERALERT, 2, 1, &databuf);
if (currentlen == -1) {
perror("append() error");
exit(EXIT_FAILURE);
}
printf("len after append:%d\n", currentlen);
//insert value for the version and flags
offset = 0;
value = 0x11;
offset = inet6_opt_set_val(databuf, offset, &value, sizeof(value));
//value1 = 0x01;
//printf("Data buffer is: %x\n",databuf);
//offset = inet6_opt_set_val(databuf, offset, &value1, sizeof(value1));
value2 = 0x01;
offset = inet6_opt_set_val(databuf, offset, &value2, sizeof(value2));
currentlen = inet6_opt_finish(extbuf, extlen, currentlen);
if (currentlen == -1)
perror("opt_finish");
//*(uint8_t)(extbuf) = 59;
printf("Data buffer is: %x\n",*(unsigned char*)(databuf));
printf("Extlen is: %d\n",extlen);
printf("Currentlen is: %d\n", currentlen);
unsigned char* temp1 = databuf;
for(j=0; j<3;j++) {
printf("Data buffer is: %d\n",*temp1);
temp1++;
}
for(i=0;i<extlen;i++) {
printf("exbuf is:%d\n",*temp);
temp++;
}
/*
cmsglen = CMSG_SPACE(extlen);
cmsg = malloc(cmsglen);
if (cmsg == NULL) {
perror("msg malloc");
exit(EXIT_FAILURE);
}
cmsg->cmsg_len = CMSG_LEN(extlen);
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_HOPOPTS;
extbuf = CMSG_DATA(cmsg);
*/
iov[0].iov_base = packet;
iov[0].iov_len = sizeof(packet);
iov[1].iov_base = extbuf;
iov[1].iov_len = sizeof(extbuf);
//iov[2].iov_base = databuf;
//iov[2].iov_len = sizeof(databuf);
msg.msg_control = cmsg;
msg.msg_controllen = cmsglen;
msg.msg_name = (struct sockaddr*)&daddr;
msg.msg_namelen = sizeof(daddr);
msg.msg_iov = &iov;
msg.msg_iovlen = 2;
msg.msg_flags = 0;
while(1) {
sleep(1);
/*if (sendto(s, (char *)packet, sizeof(packet), 0,
(struct sockaddr *)&daddr, (socklen_t)sizeof(daddr)) < 0)
perror("packet send error:");
}*/
if (sendmsg(s, &msg, 2) < 0) {
perror("sendmsg()");
}
else
printf("data sent\n");
}
exit(EXIT_SUCCESS);
}
short unsigned sequence_number()
{
number = rand();
return number;
}
RECEIVER.C
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip6.h>
#include <errno.h>
#include <netdb.h>
#define IP_TLV_ROUTERALERT 5
int print_options(void *, socklen_t);
int main(void)
{
int s,i;
struct sockaddr_in6 saddr;
char packet[80];
int setsock_offset = 1;
//-----for ancillary data
int currentlen;
void *extptr;
struct sockaddr_in6 addr;
struct msghdr msg;
struct cmsghdr *cmsgptr;
struct iovec iov;
void *extbuf;
socklen_t extension_len;
socklen_t extlen;
socklen_t cmsgspace;
char databuf[80];
char sender_ip[40];
//sender_ip = (char*)malloc(sizeof(char));
printf("size :%d\n",sizeof(sender_ip));
strcpy(sender_ip, "fe80::921b:eff:fe03:637d");
printf("Sender ip: %s\n", sender_ip);
addr.sin6_family = AF_INET6;
addr.sin6_port = 0;
inet_pton(AF_INET6, sender_ip, (struct in6_addr *)&addr.sin6_addr.s6_addr);
if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}
if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &setsock_offset, sizeof(setsock_offset)) < 0)
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
currentlen = inet6_opt_init(NULL,0);
if (currentlen == -1)
{
perror("1st opt_init");
exit(EXIT_FAILURE);
}
currentlen = inet6_opt_append(NULL,0,currentlen, IPV6_TLV_ROUTERALERT, 2, 1, NULL);
if (currentlen == -1)
{
perror("1st append");
exit(EXIT_FAILURE);
}
currentlen = inet6_opt_finish(NULL, 0, currentlen);
if (currentlen == -1)
{
perror("1st finish");
exit(EXIT_FAILURE);
}
extension_len = currentlen;
cmsgspace = CMSG_SPACE(extension_len);
cmsgptr = malloc(cmsgspace);
if (cmsgptr == NULL)
{
perror("malloc");
exit(EXIT_FAILURE);
}
extptr = CMSG_DATA(cmsgptr);
msg.msg_control = cmsgptr;
msg.msg_controllen = cmsgspace;
iov.iov_base = databuf;
iov.iov_len = 1;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
msg.msg_name = (struct sockaddr *)&addr;
msg.msg_namelen = sizeof(addr);
memset(packet, 0, sizeof(packet));
socklen_t *len = (socklen_t *)sizeof(saddr);
int fromlen = sizeof(saddr);
while(1)
{
printf("Waiting for packets...\n");
if (recvmsg(s, &msg, 0) == -1)
{
perror("packet receive error:");
return;
}
if (msg.msg_controllen != 0 &&
cmsgptr->cmsg_level == IPPROTO_IPV6 &&
cmsgptr->cmsg_type == IPV6_HOPOPTS ) {
print_options(extptr, extension_len);
}
}
}
int print_options(void *extbuf, socklen_t extlen)
{
struct ip6_hbh *ext;
int currentlen;
uint8_t type;
socklen_t len;
void *databuf;
int offset;
uint8_t value;
uint8_t value1;
ext = (struct ip6_hbh *)extbuf;
printf("nxt header %u, len: %u (bytes%d)\n", ext->ip6h_nxt, ext->ip6h_len, (ext->ip6h_len + 1)*8);
currentlen = 0;
while(1)
{
currentlen = inet6_opt_next(extbuf, extlen, currentlen, &type, &databuf);
if(currentlen == -1)
break;
printf("Received opt %u len %u\n", type, len);
switch(type)
{
case IPV6_TLV_ROUTERALERT:
offset = 0;
offset = inet6_opt_get_val(databuf, offset, &value, sizeof(value) );
printf("1 byte field %x\n", value);
offset = inet6_opt_get_val(databuf, offset, &value1, sizeof(value1) );
printf("2 byte field %x\n", value1);
break;
default:
printf("unknown option :%x\n", type);
break;
}
}
return(0);
}
References that I have been using is from the RFC 3542.
If you'll can provide me with some reference as to where can I get some more info would be great, or is the only way to do is, to create ethernet_level raw sockets and get hold of everything in user-space.(which I think is unreasonable, as there has to be a way to do some testing on the user-space as well)
Upvotes: 0
Views: 1006
Reputation: 406
In your receiver.c, you create a rawip socket with:
(s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW))
the problem lies in IPPROTO_RAW, you can get its description at:
http://manpages.ubuntu.com/manpages/hardy/man7/raw.7.html
" A protocol of IPPROTO_RAW implies enabled IP_HDRINCL and is able to send any IP protocol that is specified in the passed header. Receiving of all IP protocols via IPPROTO_RAW is not possible using raw sockets. "
you may create your socket using NEXTHDR_HOP, instead of IPPROTO_RAW.
I myself not tried, just get from doc / code.
Upvotes: 1