LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Raw socket programming with C (https://www.linuxquestions.org/questions/programming-9/raw-socket-programming-with-c-503513/)

arabindav 11-21-2006 03:39 AM

Raw socket programming with C
 
Hello All,

I am facing problem with code to send and receive packets using RAW sockets. The packets are layer 2 control packets. Your help in this regard is highly appreciated.

Following is the code used to send the packets:
==============================================================================================
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if_ether.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <netinet/ether.h>

#define ETHERTYPE_LEN 2
#define MAC_ADDR_LEN 6

typedef unsigned char MacAddress[MAC_ADDR_LEN];
extern int errno;

int main()
{
int sockFd = 0, retValue = 0;
char buffer[BUFFER_LEN], dummyBuf[50];
struct sockaddr_ll destAddr;
short int etherTypeT = htons(0x8200);
MacAddress localMac = {0x00, 0x08, 0xA1, 0x8E, 0xE4, 0x52};
MacAddress destMac = {0x00, 0x17, 0x9A, 0xB3, 0x9E, 0x16};

memset(&destAddr, 0, sizeof(struct sockaddr_ll));
memset(buffer, 0, BUFFER_LEN);

if((sockFd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
printf("ERROR! socket() call failed (Error No: %d \"%s\").\n", errno, trerror(errno));
exit(1);
}
printf("Socket creation success.\n");

destAddr.sll_family = htons(PF_PACKET);
destAddr.sll_protocol = htons(ETH_P_ALL);
destAddr.sll_halen = 6;
destAddr.sll_ifindex = 2;
memcpy(&(destAddr.sll_addr), destMac, MAC_ADDR_LEN);

/* Ethernet Header Construction */
memcpy(buffer, localMac, MAC_ADDR_LEN);
memcpy((buffer+MAC_ADDR_LEN), destMac, MAC_ADDR_LEN);
memcpy((buffer+(2*MAC_ADDR_LEN)), &(etherTypeT), sizeof(etherTypeT));

/* Add some data */
memset(dummyBuf, 0xa0, sizeof(dummyBuf));
memcpy((buffer+ETHERTYPE_LEN+(2*MAC_ADDR_LEN)), dummyBuf, 50);

if((retValue = sendto(sockFd, buffer, 64, 0, (struct sockaddr *)&(destAddr), sizeof(struct sockaddr_ll))) < 0) {
printf("ERROR! sendto() call failed (Error No: %d \"%s\").\n", errno, strerror(errno));
exit(1);
}
printf("Send success (%d).\n", retValue);

return(0);
}
==========================================================================================

The queries are as follows:
1. The sll_addr in struct sockaddr_ll is of length 8. Is this where we assign the destination mac address? If yes, why is it 8 bytes not 6 bytes and is the assignment done fine?

2. Is sll_ifindex in struct sockaddr_ll interface index? How to get interface index from the OS?

3. The code executes perfectly ( no errors). However, the packet is not received (using recvfrom) at the destination. Do I have to construct the complete packet from preamble to FCS?

4. What about binding the socket to some address?

Please let me know what is the problem in the above code. I used tcpdump to capture the packet but it does not.

Thanks.

theNbomr 11-21-2006 10:12 AM

Have you used a packet sniffer, such as ethereal, or whatever it is called now, to see if the packet actually makes it onto the wire? Are you sure you have permission to transmit at this low level as a non-root user? A quick scan of your source code doesn't reveal anything obvious to me. It is helpful, when posting source code, to wrap the code in
Code:

#include <your source code>
tags to preserve the formatting and readability.

--- rod.

Shioni 11-21-2006 10:24 AM

You need to be root to use raw sockets!

arabindav 11-21-2006 09:44 PM

Thanks for your reply.

Yes, I am using tcpdump to check the packet transmission.

The command: tcpdump -n -i eth1 ether dst <destination MAC>

It's not capturing the packet. And yes, I am executing the code and tcpdump command in superuser mode.

Any suggestions?

Arabinda

primo 11-23-2006 12:24 AM

There's a SIOCGIFINDEX ioctl() to get interface index. You're better using libpcap. Linux has changed a lot of things through kernel versions to rely on a single way to get packets straight. In some versions you'd get duplicated packets for the loopback interface, etc. Libpcap is surprisingly easy to learn, just try it.

Son_of_Merlin 12-28-2006 10:29 AM

I'm having exactly the same problem but ...
 
Hi Arabindav!

I'm having exactly the same problems as you with code that used to work perfectly under my old distro SuSE 8. I'm not an expert (yet) but I can help you with some of your questions:-

1) The sll_addr field in a low level socket address has to accommodate ALL interfaces - not just Ether. So 8 chars are used as other addresses may require more than 6. Your assignment is quite correct. The destination MAC goes into this field starting at location 0.

2) Yes. The sll_ifindex field is the interface index (PCI bus active slot position)+2 of the NIC you are using. Index 0 is the loopback device and 1 is the 'default' device. Real hardware always starts at 2. You can scan your PCI bus using ioctl with SIOCGIFCONF. You need to call it twice. Once to get the size of the result buffer and then again to populate the buffer. I've got working code if you need it.

3) No. You do not need preamble and FCS. This is the bit we both have in common. Are you using Fedora Core by any chance? Like you, I get no errors on transmission (sendto) but nothing valid appears to be leaving my socket. The recipient machine's indicators blink but they do not respond and tcpdump shows nothing leaving my interface.

4) Naming the socket (binding) is not mandatory and will not affect your results. It will only serve to filter out traffic from a specific interface. The sending address (struct sockaddr_ll) is the bit that sets up the link layer - which for RAW PACKET sockets has always had me confused since we are constructing the full protocol stack from Ether right down to application data ourselves complete with header checksums and options!

On another point - you have network-oriented your address family field:

"destAddr.sll_family = htons(PF_PACKET);"

You do not need to do this. The family is host order. It is only network-facing values that need to be in net order.

If you get a working result (and mine always did work under SuSE 8 and prior) please could you let me know.

If you want to see the PCI bus scan I can post it for you but it's rather a lot of kit for one bulletin. It's ever so simple though.

If you get working before me can you let me know what you did - if I before you I'll post the relevant mods here.

Cheers,
SOM

can26_manish 10-22-2007 04:48 AM

Hi Arabindav,

Is your prob solved. Actually I saw this post and I am doing the same thing. For my case also there is no compilation error but I am not able to capture the packet through ethereal.
I want to ask one thing. I am creating a packet a sending it through interface eth0. If i run ethereal on eth0 will it capture the packet.

chandan_raka 08-10-2009 03:10 AM

RAW socket
 
Hey,

I also used your program and faces similar issue.

However, another version of the similar program atleast sends some data though not in format of tcp dump..

sock=socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
if(sock < 0)
{
perror("socket:");
}

struct ifreq ifReq;
memset(&ifReq, 0, sizeof(ifReq));
strncpy(ifReq.ifr_name, devname, sizeof(ifReq.ifr_name));
if (ioctl(sock,SIOCGIFINDEX,&ifReq)) {
printf("unable to get index\n");
return -1;
}

struct sockaddr_ll sockAddress;
sockAddress.sll_ifindex = ifReq.ifr_ifindex;
sockAddress.sll_family = AF_PACKET;
sockAddress.sll_protocol = htons(ETH_P_IP);
sockAddress.sll_halen = 6;
readmac(sockAddress.sll_addr, destmac);

a = sendto(sock,&buf,len,0,(struct sockaddr*) &sockAddress, sizeof(sockAddress));
if (a < 0)
printf("sendto failed \n");
return a;



here we are reading the MAC from command line..

orgcandman 08-10-2009 12:47 PM

Code:

/* Ethernet Header Construction */
memcpy(buffer, localMac, MAC_ADDR_LEN);
memcpy((buffer+MAC_ADDR_LEN), destMac, MAC_ADDR_LEN);
memcpy((buffer+(2*MAC_ADDR_LEN)), &(etherTypeT), sizeof(etherTypeT));

This is probably not what you wanted to write. I'll let you peruse the ethernet specification to see why.


Code:

  destAddr.sll_pkttype  = PACKET_OTHERHOST;
I have things working using this.

mezo_36 06-08-2011 03:07 PM

hey guys plz help about my problem i wanna to make a syn scanner with

and this my code but it get me segmentation fault

can any one help me plz



#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<linux/ip.h>
#include<linux/tcp.h>
#include<features.h>
#include<errno.h>

#define SRC_IP "192.168.72.128"
#define DST_IP "192.168.1.1"
#define SRC_PORT 1234

#define SA struct sockaddr

unsigned short ComputeChecksum(unsigned char *data, int len)
{
long sum = 0;
unsigned short *temp = (unsigned short *)data;

while(len>1)
{
sum = *temp++;
if(sum & 0x80000000)
sum = (sum & 0xFFFF) + (sum >> 16);
len -= 2;
}

if(len)
sum = (unsigned short *) *((unsigned char *)temp);

while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);

return ~sum;
}

typedef struct PseudoHeader
{
unsigned long int source;
unsigned long int dest;
unsigned char reserved;
unsigned char protocol;
unsigned short int tcp_len;
}PseudoHeader;

int main(int argc, char **argv)
{
int send_socket;
int pkt_len;
struct iphdr *ip_header;
struct tcphdr *tcp_header;
unsigned char *packet;
unsigned char *psh;
struct sockaddr_in sin;

int range_1;
int range_2 = atoi(argv[1]);

ip_header = (struct iphdr *)packet;
tcp_header = (struct tcphdr *)(packet + sizeof(struct iphdr));
PseudoHeader *pseudo_header;

for(range_1 = 0 ; range_1 < range_2 ; range_1++)
{
sleep(1);
ip_header->version = 4;
ip_header->ihl = (sizeof(struct iphdr))/4;
ip_header->tos = 0;
ip_header->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr));
ip_header->id = htons(1234);
ip_header->frag_off = 0;
ip_header->ttl = 255;
ip_header->protocol = IPPROTO_TCP;
ip_header->check = 0;
ip_header->saddr = inet_addr(SRC_IP);
ip_header->daddr = inet_addr(DST_IP);

ip_header->check = ComputeChecksum((unsigned char *)ip_header, ip_header->ihl*4);

tcp_header->source = htons(SRC_PORT);
tcp_header->dest = htons(range_1);
tcp_header->seq = htonl(1234);
tcp_header->ack_seq = htonl(4321);
tcp_header->res1 = 0;
tcp_header->doff = (sizeof(struct tcphdr))/4;
tcp_header->syn = 1;
tcp_header->window = htons(512);
tcp_header->check = 0;
tcp_header->urg_ptr = 0;

pseudo_header->source = ip_header->saddr;
pseudo_header->dest = ip_header->daddr;
pseudo_header->reserved = 0;
pseudo_header->protocol = IPPROTO_TCP;
pseudo_header->tcp_len = htons(tcp_header->doff*4);

memcpy(psh, pseudo_header, sizeof(PseudoHeader));
memcpy((psh + sizeof(PseudoHeader)), tcp_header, tcp_header->doff*4);


tcp_header->check = ComputeChecksum(psh, sizeof(psh));

sin.sin_family = AF_INET;
sin.sin_port = tcp_header->dest;
sin.sin_addr.s_addr = ip_header->daddr;

send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if(send_socket == -1)
{
perror("cannot open the socket\n");
exit(-1);
}
pkt_len = ntohs(ip_header->tot_len);

if(sendto(send_socket, packet, pkt_len, 0, (SA *)&sin, sizeof(sin)) == -1)
{
perror("cannot send the packet\n");
exit(-1);
}
else
printf("packet sent to port %d\n", range_1);

close(send_socket);
}
}

plz help realy guys wana to know where my fault

primo 06-08-2011 03:21 PM

Your program segfaults because this pointer isn't initialized.

unsigned char *packet;

It must be:

unsigned char packet[IP_MAXPACKET]; /* #define'd in <netinet/ip.h> */

dwhitney67 06-08-2011 03:29 PM

Welcome to LQ.

Rather than resurrect this old thread, you should have thought about creating a new one. Anyhow, it would seem that your first issue is with the following line of code:
Code:

unsigned char *packet;
You will need to allocate space for the packet before you can begin to use it. Try something like:
Code:

unsigned char *packet = malloc(sizeof(struct ip) + sizeof(struct tcphdr) + sizeOfTheData);
I did not see you working with any data (payload), thus I guess it is safe to assume that sizeOfTheData is zero (0) in your case.


P.S. I see that you are using struct iphdr, whereas in code I've developed in the past, I used struct ip.

mezo_36 06-08-2011 05:26 PM

am realy thx you guys realy and hope to keep in touch with us brothers

mezo_36 06-09-2011 04:51 AM

sorry i have another segfault the program seg fault in pseudoheader

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<linux/ip.h>
#include<linux/tcp.h>
#include<features.h>
#include<errno.h>

#define SRC_IP "192.168.72.128"
#define DST_IP "192.168.1.1"
#define SRC_PORT 1234

#define SA struct sockaddr

unsigned short ComputeChecksum(unsigned char *data, int len)
{
long sum = 0;
unsigned short *temp = (unsigned short *)data;

while(len>1)
{
sum = *temp++;
if(sum & 0x80000000)
sum = (sum & 0xFFFF) + (sum >> 16);
len -= 2;
}

if(len)
sum = (unsigned short *) *((unsigned char *)temp);

while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);

return ~sum;
}

typedef struct PseudoHeader
{
unsigned long int source;
unsigned long int dest;
unsigned char reserved;
unsigned char protocol;
unsigned short int tcp_len;
}PseudoHeader;

int main(int argc, char **argv)
{
int send_socket;
int pkt_len;
struct iphdr *ip_header;
struct tcphdr *tcp_header;
unsigned char *packet;
unsigned char *psh;
struct sockaddr_in sin;

int range_1;
int range_2 = atoi(argv[1]);

ip_header = (struct iphdr *)packet;
tcp_header = (struct tcphdr *)(packet + sizeof(struct iphdr));
PseudoHeader *pseudo_header;

for(range_1 = 0 ; range_1 < range_2 ; range_1++)
{
sleep(1);
ip_header->version = 4;
ip_header->ihl = (sizeof(struct iphdr))/4;
ip_header->tos = 0;
ip_header->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr));
ip_header->id = htons(1234);
ip_header->frag_off = 0;
ip_header->ttl = 255;
ip_header->protocol = IPPROTO_TCP;
ip_header->check = 0;
ip_header->saddr = inet_addr(SRC_IP);
ip_header->daddr = inet_addr(DST_IP);

ip_header->check = ComputeChecksum((unsigned char *)ip_header, ip_header->ihl*4);

tcp_header->source = htons(SRC_PORT);
tcp_header->dest = htons(range_1);
tcp_header->seq = htonl(1234);
tcp_header->ack_seq = htonl(4321);
tcp_header->res1 = 0;
tcp_header->doff = (sizeof(struct tcphdr))/4;
tcp_header->syn = 1;
tcp_header->window = htons(512);
tcp_header->check = 0;
tcp_header->urg_ptr = 0;

pseudo_header->source = ip_header->saddr;
pseudo_header->dest = ip_header->daddr;
pseudo_header->reserved = 0;
pseudo_header->protocol = IPPROTO_TCP;
pseudo_header->tcp_len = htons(tcp_header->doff*4);

memcpy(psh, pseudo_header, sizeof(PseudoHeader));
memcpy((psh + sizeof(PseudoHeader)), tcp_header, tcp_header->doff*4);


tcp_header->check = ComputeChecksum(psh, sizeof(psh));

sin.sin_family = AF_INET;
sin.sin_port = tcp_header->dest;
sin.sin_addr.s_addr = ip_header->daddr;

send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if(send_socket == -1)
{
perror("cannot open the socket\n");
exit(-1);
}
pkt_len = ntohs(ip_header->tot_len);

if(sendto(send_socket, packet, pkt_len, 0, (SA *)&sin, sizeof(sin)) == -1)
{
perror("cannot send the packet\n");
exit(-1);
}
else
printf("packet sent to port %d\n", range_1);

close(send_socket);
}
}

dwhitney67 06-09-2011 05:46 AM

"Give a person a fish, and you feed them for the night. Teach them to fish, and you feed them for a lifetime."


It appears that you did not learn anything from the previous problem you had; it is identical to your new one.
Code:

PseudoHeader *pseudo_header;
You need to allocate space for the pseudo_header, either on the heap or on the stack.

P.S. IMHO, you should take a step back from playing with raw sockets, and learn the basics of C programming first. I still see the same error (first one you had) in the latest code you posted.


All times are GMT -5. The time now is 12:03 AM.