0

I am trying to write a function that takes a stream of bytes (including ethernet header and perhaps upper layer protocols encapsulated within the ethernet packet as well) and send it out on the network on a particular interface.

Here is a summary of my code:

// create socket
int s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s < 0) {
    // error handling
}

// set up to just receive/send packets on one interface (stored in the variable iface_name e.g. eth0)
struct ifreq ifr;
bzero(&ifr, sizeof(struct ifreq));
strncpy(ifr.ifr_ifrn.ifrn_name, iface_name, IFNAMSIZ);
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
    // error handling
}

// set up socaddr for write
struct sockaddr sa;
sa.sa_family = PF_PACKET;
sa.sa_data = htons(ETH_P_ALL);

// write to wire
// buf has type char* and len has type int
// buf contains ethernet header, followed by payload (e.g. ARP packet or IP packet)
if ( sendto(s, buf, len, 0, &sa, sizeof(struct sockaddr) ) < 0 ) {
    perror("sendto");
    // more error handling
}

I get the error

sendto: Invalid argument

How can I fix this error?

My initial guess is that this is somehow caused by the sa argument, since all the others are fairly standard and there's not much to go wrong. I could replace this with an argument of sockaddr_ll type as in this example, but this would mean extracting the header information from buf and this seems a little pointless since it's already there, ready to go. There must be a better way? Encapsulate, unencapsulate, re-encapsulate, send seems like it has too many unnecessary steps. I am writing an underlying interface for some pre-existing code, so there is no way I can adapt the input to not already have the data-link layer headers included.

Froskoy
  • 2,967
  • 5
  • 20
  • 21
  • Take a look here. http://austinmarton.wordpress.com/2011/09/14/sending-raw-ethernet-packets-from-a-specific-interface-in-c-on-linux/ – gifnoc-gkp Jul 31 '13 at 13:19
  • I think that's close, but what do I fill in for the destination MAC address in sll_addr? If possible, I want to avoid having to extract this from my input data (since the packet's already constructed, so I don't see why I have to tear it apart). I guess I understand if this isn't possible though? – Froskoy Jul 31 '13 at 13:22
  • Ahem. http://stackoverflow.com/questions/1519585/how-to-get-mac-address-for-an-interface-in-linux-using-a-c-program – gifnoc-gkp Jul 31 '13 at 13:28
  • So you're saying that in the MY_DEST_MAC in the example link you sent, I fill in my own MAC address? That seems a little counter intuitive, since I'm not sending the frame to myself. The fact that I have to even fill in a MAC address makes me think the card is going to do some additional encapsulation, which I don't want? – Froskoy Jul 31 '13 at 13:33
  • https://en.wikipedia.org/wiki/Ethernet_frame. Yes, you put your own mac address (how else would the router know to send it back to you? ) The way it works is, you put a source ip, and a destination ip, and you put a source mac address (yours), and then you put your router's mac address as the destination. Then when the router gets it, it keeps the source ip and destination ip, but changes the mac addresses to its own as the source, and then as the NEXT router as the mac address. This keeps happening until the packet reaches the destination. – KrisSodroski Jul 31 '13 at 13:50
  • The router would know, because I already have the link layer header information included in my input data - it's a fully constructed ethernet frame already! – Froskoy Jul 31 '13 at 13:52
  • so what data is there? can you post that? – KrisSodroski Jul 31 '13 at 13:52
  • `buf` consists of a full ethernet header, followed by (probably) an IP header or ARP packet. All addresses are already in network byte order and it's ready to send out on the interface, as is. – Froskoy Jul 31 '13 at 13:55
  • if ( sendto(s, buf, len, 0, &sa, sizeof(struct sockaddr) ) < 0 ): Why this? sizeof(struct sockaddr) ) < 0; isn't that boolean and not an integer value like that argument reuqires? – KrisSodroski Jul 31 '13 at 14:02
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/34538/discussion-between-magn3s1um-and-froskoy) – KrisSodroski Jul 31 '13 at 14:04

1 Answers1

0

its your libraries:

http://linux.die.net/man/7/raw see the header definition and look at how he makes his socket he's not using htons, but rather: IPPROTO_RAW located in

  #include <netinet/in.h>
Veger
  • 37,240
  • 11
  • 105
  • 116
KrisSodroski
  • 2,796
  • 3
  • 24
  • 39