Archive for May, 2008

Weekly Report

Monday, May 26th, 2008

I will be attempting to write one of these every week from now on, if I can remember to. This particular report goes back to shortly after I started working on MPLS.

Accomplished Last Week:

  • Wrote MPLS-Needle, a tool to inject semi-custom MPLS packets into the network.
  • Read through a lot of code already written such as Ayame, and the OpenBSDs currently in development work.

Working on This Week:

  • Not much as I have 2 more weeks of this semester left before I get 5 weeks off to work on MPLS.
  • If time I will continue to read through code and possibly look at porting some over.

Injecting Custom Packets in FreeBSD

Saturday, May 24th, 2008

Well, over the past couple of weeks I have been working on the begginings of my MPLS implementation. The first step was to write a program that can inject semi-customisable MPLS packets into the FreeBSD networking stack. I found when I started this project there was very few resources that I could find that helped me complete this. So, in an effort to help anyone else attempting to write an injection tool I figured I might write a short post (well as short as I can keep it) on how to acheive this. I’ll try and keep it brief.

The first step is to create the datagram packet that will be sent.

uint8_t datagram[1500]

where the size of the array is the number of bytes you are wanting to send.
Once the datagram is created you need to fill it with the packets header values. Most types of headers you will already find defined inside the /src/netinet/ folder. These are normally very easy to use. They are created as follows:

struct ether_header *eth = (struct ether_header *)(datagram);
struct ip *iph = (struct ip *)(datagram + sizeof(uint32_t) + sizeof(struct ether_header));
struct icmphdr *icmph = (struct icmphdr *)(datagram + sizeof(struct ip) + sizeof(struct ether_header));

In this example the struct is defined, with a pointer which also points to the point in the datagram where the header needs to start. For instance, the icmp header needs to point to the next byte after the IP header, which is the size of the ip header + the size of the ethernet header, past the start of the datagram. Once these have been created it’s fairly simple to assign values to the headers, like so:

iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = ip4_tos;
iph->ip_len = htons((iph->ip_hl<<2) + 8 + 20);

I’ll leave it up to you to figure out the rest of the values, which is pretty easy if you look at the struct definitions.

If you require a header that is not already defined in the netinet package, the easiest way I found to do this was to create a int larger than the size of the header, then once it has had the values inserted into it, use byte shifting to make the header values lined up correctly. Then the values are copied into the datagram using memcpy.

uint32_t mplsh;
mplsh = htonl(mpls_label << 12 | mpls_qos << 9 | mpls_bos_flag << 8 | mpls_ttl);
memcpy(&datagram[14], &mplsh, 4);

After this the packet has been created and is ready to send along the wire. To do this we use a BPF device. So, we need to find a spare BPF device, open it up, and writing the packet to it.

To find a spare device, you basically have to poll through every possible BPF device until you find one that isnt being used.

int
dl_bpf_open_dev(char *dev, const size_t len)
{
int i=0, fd;
do {
snprintf(dev, len, "/dev/bpf%d", i);
if ((fd = open(dev, O_RDWR)) == -1) {
if (errno == EBUSY)
continue;
else {
fprintf(stderr, "could not open %s\n", dev);
return -1;
}
}
else break;
}
while (++i < 32768);
return fd;
}

Once this is done you need to open the device to allow you to write to it.

int
dl_bpf_open(const char *ifname)
{
struct ifreq ifreq;
char dev[16];
int fd;
memset(&ifreq, 0, sizeof(ifreq));
strcpy(ifreq.ifr_name, ifname);
if ((fd = dl_bpf_open_dev(dev, sizeof(dev))) == -1)
return -1;
if (ioctl(fd, BIOCSETIF, &ifreq) == -1) {
fprintf(stderr, "%s BIOCSETIF %s failed\n", dev, ifreq.ifr_name);
close(fd);
return -1;
}
return fd;
}

Note: Thank you to Matthew Luckie for giving me the code to find and open the device. ALso, if you wish to use this code, then all you need to do is make a call to dl_bpf_open() and it will do the rest for you.

Once this is done you simply need to write to the open device, then close it up and you’re all done.

if ((wb = write(fd, datagram, len)) < (ssize_t)len) {
if (wb == -1)
fprintf(stderr, "%d bytes failed\n", len);
else
printf("%d bytes sent of %d total\n", wb, len);
return -1;
}

So thats basically it. I dont think I’ve gone quite as indepth as I possibly could, but from this most people should be able to get something working. If anyone has anymore questions post them at either of my websites and I’ll get back to you. Also, if anyone out there notices a mistake I’ve made, please let me know asap, before I put too many people wrong.

EDIT: I’m having a few problems with keeping tabs and spacing formatting in the code sections, if anyone knows how to fix this please let me know.

Automatic RSS Syndication to www.driven-monkey.com

Monday, May 12th, 2008

So, all things going to plan, this post should be appearing both on my FreeBSD Contributors blog as well as my main blog, and if it doesn’t, well I’m just gonna delete it and try again.

I’m using the FeedWordpress plugin which is pretty quick and easy to install and use. All I had to do was put in the address of this blog under the Syndication tabs, change a few options to automatically update the blogs, and hey presto, the internets magic does its thing. Its gonna make life a lot simpler than having to post any work I do on MPLS on both blogs.

Hello World!!

Tuesday, May 6th, 2008

Time for the obligatory Hello World post. This FreeBSD Contributors blog will be a resource mostly on developing a networking protocol for FreeBSD, due to the nature of the Summer of Code project I am working on (MPLS in FreeBSD). This blog will be fed into my main blog, www.driven-monkey.com, but if you want to leave a comment here I’ll get back to you asap.