10

We are trying to communicate with the server listening on Linux loopback interface via raw socket and it seems like the server does not get a single packet from us. The packets we send are visible in Wireshark.

Is raw socket on loopback possible at all? (Please, don't ask why we need it: it's too complicated to explain here)

EDIT: this is how we open it

_I_RawSocket = socket( PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)))

memset( &ifr, 0, sizeof( ifr ) );
strcpy( ifr.ifr_ifrn.ifrn_name, _InterfaceName);

ioctl( _I_RawSocket, SIOCGIFINDEX, &ifr )

memset( &sll, 0, sizeof( sll ) );
sll.sll_family   = AF_PACKET;
sll.sll_ifindex  = ifr.ifr_ifindex;
sll.sll_protocol = htons( ETH_P_ALL );

bind( _I_RawSocket, (struct sockaddr *) &sll, sizeof( sll ))

The server is lighttpd and it's reachable via normal socket on localhost. netstat --raw prints empty table but I'm absolutely sure we have two functional raw sockets on normal eth devices.

Peter O.
  • 32,158
  • 14
  • 82
  • 96
jackhab
  • 17,128
  • 37
  • 99
  • 136
  • Please post: a) Exactly what type of socket you are using, is it a AF_PACKET ? b) How you are binding it, are you using bind or SO_BINDTODEVICE ? c) What is the server and what is it trying to do? Can you talk to it with an IP socket (assuming IP here)? Can you send the output of netstat --raw ? – MarkR Jul 26 '10 at 13:45
  • @MarkR: Given that he's going for raw sockets, I'm guessing SOCK_RAW. SOCK_PACKET is obsolete, anyway. – Michael Foukarakis Jul 26 '10 at 13:46
  • I find the "man 7 packet" page quite useful, please read it and see if what it describes is consistent with what you're doing. – MarkR Jul 26 '10 at 13:47
  • @mfukar I meant AF_PACKET not the obsolete "AF_INET/SOCK_RAW" – MarkR Jul 26 '10 at 13:48

2 Answers2

3

Raw sockets behave particularly fizzy with bind() and connect(), but I can't confirm that your issue lies with them. I suggest you follow a more straightforward approach:

Sender

#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>

#define DEST "127.0.0.1"

int main(int argc, char **argv)
{

 int s;
 struct sockaddr_in dst_addr;
 char packet[50];

 struct iphdr *ip = (struct iphdr *)packet;  

 if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
  perror("error:");
  exit(EXIT_FAILURE);
 }

 dst_addr.sin_family = AF_INET;
 dst_addr.sin_port = 0; /* not needed in SOCK_RAW */
 inet_pton(AF_INET, DEST, (struct in_addr *)&dst_addr.sin_addr.s_addr);
 memset(dst_addr.sin_zero, 0, sizeof(dst_addr.sin_zero));

 memset(packet, 'A', sizeof(packet));   /* payload will be all As */

 ip->ihl = 5;
 ip->version = 4;
 ip->tos = 0;
 ip->tot_len = htons(40);
 ip->frag_off = 0;  /* NF */
 ip->ttl = 64;
 ip->protocol = IPPROTO_RAW; /* this has to be IPPROTO_RAW */
 ip->check = 0;
 ip->saddr = dst_addr.sin_addr.s_addr;
 ip->daddr = dst_addr.sin_addr.s_addr;

 while(42) {
  sleep(5);
  if (sendto(s, packet, sizeof(packet), 0, 
   (struct sockaddr *)&dst_addr, (socklen_t)sizeof(dst_addr)) < 0)
   perror("uh oh:");
 }
 return(0);
}

Receiver

#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>


int main(int argc, char **argv)
{
 int s;
 struct sockaddr_in src_addr;
 char packet[50];

 if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
  perror("error:");
  exit(EXIT_FAILURE);
 }

 memset(packet, 0, sizeof(packet));
 socklen_t *len = (socklen_t *)sizeof(src_addr);
 int fromlen = sizeof(src_addr);

 while(42) {
  if (recvfrom(s, &packet, sizeof(packet), 0,
   (struct sockaddr *)&src_addr, &fromlen) < 0)
   perror("uh oh:");

  int i = sizeof(struct iphdr); /* print the payload */
  for(; i < sizeof(packet); i++) {
   printf("%c", packet[i]);
  }
  printf("\n");
 }
 return(0);
}

I hope these behave exactly like you want them to. Read man 7 raw for the gory details of why this works and more importantly man 7 packet if you want to extend it. Also, take note that IPPROTO_RAW implies the IP_HDRINCL socket option, which is why we're constructing the ip header ourselves - although the IP checksum and total length are computed and filled in by the kernel, still.

edit: In addition, if you wanted a raw socket with which to send valid data to an application like lighttpd, you'd have to match the protocol argument to socket() as well as provide valid values for the IP header fields. A proper ethernet header is not mandatory - the only important field will be filled for you by the kernel stack.

BoppreH
  • 8,014
  • 4
  • 34
  • 71
Michael Foukarakis
  • 39,737
  • 6
  • 87
  • 123
0

Please make sure bind to if_index

if (ioctl(sock, SIOCGIFINDEX, &stEthReq ) < 0 )
{
    printf( "failed to get IF index!" );
    return -1;
}
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sll_family   = AF_PACKET;
client_addr.sll_ifindex  = stEthReq.ifr_ifru.ifru_ivalue;
client_addr.sll_protocol = VOS_HTONS(usEthType);
ret = bind(sock,(struct sockaddr *)(&client_addr), sizeof(client_addr));
Daniel
  • 631
  • 2
  • 7
  • 14