Basic example af_packet raw server and client

  • In this program, you are going to learn

  • How to create a Socket ?

  • How to bind a socket ?

  • How to send a data ?

  • How to recv a data ?

Let us answer few basic questions in this socket

What does socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) do?

How can I handle errors when creating a raw socket for packet capturing?

Are there specific privileges required to create a raw packet socket?

What kind of errors can occur when using a raw packet socket?

How do I handle errors when binding a raw packet socket?

What is the significance of error code EPERM when dealing with raw packet sockets?

How do I handle errors when using recv and send to capture packets and send packets with a raw socket?

Is it important to close the raw packet socket on error?

How do I handle timeouts when capturing packets with a raw packet socket?

Is it possible to capture packets on a specific network interface with a raw packet socket?

How do I handle errors related to socket file descriptor management?

https://www.plantuml.com/plantuml/svg/LO-n3e8m68JtFaLTJ34Td7412KIZYKOm9YvDQNy24IZfNp3nwGLSSBoxxowv09sqhczgid8bD42namfgcPCv83uQzGB7maHSm-WKPvocb-WaRk63qzAP5bcS7SHLXEUpv-s8drUjPbQ-nQ_8AKDdU-NefANMTkEj4Um0LaoAKwm-O0gsyEOT2shusydxee2Htz-J9Bw9zFYCETrEA1jCfJrL6uH5OqpGcOu4qEhntnS=
  • There are many functions used in socket. We can classify those functions based on functionalities.

    • Create Socket

    • Bind Socket

    • Recv data_packet

    • Close socket

  • socket() is used to create a new socket. For example,

raw_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
  • bind() is used to associate the socket with a specific address and port. For example,

ret = bind(raw_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
  • recv is used in network programming to receive data from a connected socket. For example,

ret = recv(raw_socket, buffer, BUFFER_SIZE, 0);
  • close is used to close the socket To free up system resources associated with the socket. For example,

(void)close(raw_socket);
  • See the full program below,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netpacket/packet.h>
#include <arpa/inet.h>
#include <net/ethernet.h>
#include <signal.h>
#include <net/if.h>

#define BUFFER_SIZE 1500

int main() 
{
  int raw_socket;
  int ret;
  struct sockaddr_ll 
  server_addr;
  char buffer[BUFFER_SIZE];

  raw_socket = socket(AF_PACKET, 
               SOCK_RAW, 
               htons(ETH_P_ALL));

  if (raw_socket < 0) {
    perror("socket");
    return -1;
  }

  memset(&server_addr, 0, 
  sizeof(server_addr));
  server_addr.sll_family = AF_PACKET;
  server_addr.sll_protocol =
  htons(ETH_P_ALL);
  server_addr.sll_ifindex = 
  if_nametoindex("lo");
  
  ret = bind(raw_socket, 
  (struct sockaddr *)&server_addr, 
  sizeof(server_addr));
 
  if (ret < 0) {
    perror("bind");
    (void)close(raw_socket);
    return -2;
  }

  ret = recv(raw_socket, 
  buffer, BUFFER_SIZE, 0);
  
  if (ret < 0) {
    perror("recv");
    (void)close(raw_socket);
    return -3;
  } else {
    printf("recevied = %s\n", 
    buffer);
  }

  (void)close(raw_socket);

  return 0;
}
1$ gcc -o server server.c
2
3$ sudo ./server
4
5recevied = HI
https://www.plantuml.com/plantuml/svg/NOzF2u8m6CRl-nJh4ZDsw6mNJPH28L4Zw3AclgAaJlPEWpvzQXVf-FpxmUEWaTgCNKjsfeOEA0woW5RcP0s8ZQfuWM5k86BN2_sCq_JcXI9n7vpMHlN8_EmYOk56aMMTY9qtVScqV8lVa5E6He-5eOkMPQaFrXv1Jw35eZZ5vWEgOXjlvI3ySVAngc3kd-z1u2SYlJvzJezBbKsgAQsYLGYRnPoWKGDnPj3yxmi=
  • There are many functions used in socket. We can classify those functions based on functionalities.

    • Create Socket

    • Bind Socket

    • Send data_packet

    • Close socket

  • socket is used to create a new socket. For example,

raw_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
  • bind() is used to associate the socket with a specific address and port. For example,

ret = bind(raw_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
  • send is used in network programming to send data over a connected socket. For example,

ret = send(raw_socket, buffer, BUFFER_SIZE, 0);
  • close is used to close the socket To free up system resources associated with the socket. For example,

(void)close(raw_socket);
  • See the full program below,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <signal.h>
#include <net/if.h>

#define BUFFER_SIZE 1500

int main(void) 
{
  int raw_socket;
  int ret;
  struct sockaddr_ll 
  server_addr;
  char buffer[BUFFER_SIZE];

  raw_socket = socket(AF_PACKET, 
               SOCK_RAW, 
               htons(ETH_P_ALL));

  if (raw_socket < 0) {
    perror("socket");
    return -1;
  }

  memset(&server_addr, 0, 
  sizeof(server_addr));
  server_addr.sll_family = AF_PACKET;
  server_addr.sll_protocol = 
  htons(ETH_P_ALL);
  server_addr.sll_ifindex = 
  if_nametoindex("lo");
  
  ret = bind(raw_socket, 
  (struct sockaddr *)&server_addr, 
  sizeof(server_addr));
 
  if (ret < 0) {
    perror("bind");
    (void)close(raw_socket);
    return -2;
  }

  sprintf(buffer, "%s", "HI");
  ret = send(raw_socket, 
  buffer, BUFFER_SIZE, 0);
  
  if (ret == -1) {
    perror("send");
    (void)close(raw_socket);
    return -3;
  } else {
    (void)printf("SendingMessage = %s\n",
    buffer);
  }

  (void)close(raw_socket);

  return 0;
}

1$ gcc -o client client.c
2
3$ sudo ./client
4
5SendingMessage = HI
https://www.plantuml.com/plantuml/svg/LP31JiCm44Jl_ehj1Tbj3Zqd83LK3g2sKDMjaBXOYRDHBDAuyZgfuEj90eToMitkx1jfLXHo7xfpmsQXnZC2NNA3JLwmwS1YSkOJ0qyplK_N6tcCGBsjD_gGlaTG1zSIbyTdlTVfTYj4mkB2jYNt-LN_FaR0AVZE11XrNfP-Bku8VOzUZoe2ij_eAdwpcpWM7c2Pi6jj6mJ-DopSm-jfftTIgVH9AY704l0l9C5YZwR_brnqLOL3mkCfo-H1gvSF6S5oX2yMDc7ObXEMnRntjXIcSOGtWC58mLtOQZ0E1Vq0
  • There are many functions used in socket. We can classify those functions based on functionalities.

    • Create Socket

    • Bind Socket

    • Recv data_packet

    • Close socket

  • socket() is used to create a new socket. For example,

raw_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
  • bind() is used to associate the socket with a specific address and port. For example,

ret = bind(raw_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
  • recv is used in network programming to receive data from a connected socket. For example,

ret = recv(raw_socket, buffer, BUFFER_SIZE, 0);
  • close is used to close the socket To free up system resources associated with the socket. For example,

(void)close(raw_socket);
  • See the full program below,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netpacket/packet.h>
#include <arpa/inet.h>
#include <net/ethernet.h>
#include <signal.h>
#include <net/if.h>

#define BUFFER_SIZE 1500
#define NUM_MESSAGES 10

int main() 
{
  int raw_socket;
  int ret, i;
  struct sockaddr_ll 
  server_addr;
  char buffer[BUFFER_SIZE];

  raw_socket = socket(AF_PACKET, 
               SOCK_RAW, 
               htons(ETH_P_ALL));

  if (raw_socket < 0) {
    perror("socket");
    return -1;
  }

  memset(&server_addr, 0, 
  sizeof(server_addr));
  server_addr.sll_family = AF_PACKET;
  server_addr.sll_protocol =
  htons(ETH_P_ALL);
  server_addr.sll_ifindex = 
  if_nametoindex("lo");
  
  ret = bind(raw_socket, 
  (struct sockaddr *)&server_addr, 
  sizeof(server_addr));
 
  if (ret < 0) {
    perror("bind");
    (void)close(raw_socket);
    return -2;
  }

  i = 0;
  while (i < NUM_MESSAGES) {
   ret = recv(raw_socket, 
   buffer, BUFFER_SIZE, 0);
  
   if (ret > 0) {
     printf("recevied = %s\n", 
     buffer);
   } else {
     perror("recv");
     break;
  }
  ++i;
  }

  (void)close(raw_socket);

  return 0;
}
 1$ gcc -o server server.c
 2
 3$ sudo ./server
 4
 5recevied = hello server!
 6recevied = hello server!
 7recevied = hello server!
 8recevied = hello server!
 9recevied = hello server!
10recevied = hello server!
11recevied = hello server!
12recevied = hello server!
13recevied = hello server!
14recevied = hello server!
https://www.plantuml.com/plantuml/svg/NP1FRy8m3CNl-HJcCYMG0-Tsa-XGkat0XWXeqYvH_xXgj49Gd8AsJx-qsm7jP3tx-VSiBoWKFlJ7Zar2YqS4EXSLTaN9nW5Bo5MV67YMcsssNAcz1FssN9bTzYwX3Uv4NEsVpTPawxKGAKjAUwgvBwxcTr42f-3xAi2WYxhsKt57w2_epQ0aaFr6r_2RtiYny03pb5rRso7mlsBX7buF6xDHMcTFIWi1be1_8ObuAVvBBlkcmPZmUCXpjJFwvKD9c0_msSocBDf7B4lunTbQL9qZl0548mLtPejeZ0_w0G==
  • There are many functions used in socket. We can classify those functions based on functionalities.

    • Create Socket

    • Bind Socket

    • Send data_packet

    • Close socket

  • socket is used to create a new socket. For example,

raw_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
  • bind() is used to associate the socket with a specific address and port. For example,

ret = bind(raw_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
  • send is used in network programming to send data over a connected socket. For example,

ret = send(raw_socket, buffer, BUFFER_SIZE, 0);
  • close is used to close the socket To free up system resources associated with the socket. For example,

(void)close(raw_socket);
  • See the full program below,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <signal.h>
#include <net/if.h>

#define BUFFER_SIZE 1500
#define NUM_MESSAGES 10

int main(void) 
{
  int raw_socket;
  int ret, i;
  struct sockaddr_ll 
  server_addr;
  char buffer[BUFFER_SIZE];

  raw_socket = socket(AF_PACKET, 
               SOCK_RAW, 
               htons(ETH_P_ALL));

  if (raw_socket < 0) {
    perror("socket");
    return -1;
  }

  memset(&server_addr, 0, 
  sizeof(server_addr));
  server_addr.sll_family = AF_PACKET;
  server_addr.sll_protocol = 
  htons(ETH_P_ALL);
  server_addr.sll_ifindex = 
  if_nametoindex("lo");
  
  ret = bind(raw_socket, 
  (struct sockaddr *)&server_addr, 
  sizeof(server_addr));
 
  if (ret < 0) {
    perror("bind");
    (void)close(raw_socket);
    return -2;
  }

  i = 0;
  while (i < NUM_MESSAGES) {
   sprintf(buffer, "%s", "hello server!");
   ret = send(raw_socket, 
   buffer, BUFFER_SIZE, 0);
  
   if (ret == -1) {
     perror("send");
     break;
   } else {
     (void)printf("SendingMessage = %s\n",
     buffer);
   }
  ++i;
  }

  (void)close(raw_socket);

  return 0;
}

 1$ gcc -o client client.c
 2
 3$ sudo ./client
 4
 5SendingMessage = hello server!
 6SendingMessage = hello server!
 7SendingMessage = hello server!
 8SendingMessage = hello server!
 9SendingMessage = hello server!
10SendingMessage = hello server!
11SendingMessage = hello server!
12SendingMessage = hello server!
13SendingMessage = hello server!
14SendingMessage = hello server!

Default Domain:

By default, the socket is configured to work in the AF_PACKET domain, handling all types of network data.

Additional Domain Support:

We expand the socket’s capabilities to also function in the PF_PACKET domain, allowing it to operate similarly to AF_PACKET.

Socket Creation:

We set up a network connection point known as a socket using socket(PF_PACKET, SOCK_RAW, IPPROTO_UDP).

Working Scenario:

Despite the change in domain to PF_PACKET, the socket continues to operate the same way, handling general network data.

Default Protocol Support:

By default, the socket is configured to support the capture of all Ethernet frames (ETH_P_ALL protocol).

Additional Protocol:

The socket is designed to seamlessly support an additional protocol, namely ETH_P_PAE.

Socket Creation:

A socket is created using the socket(AF_PACKET, SOCK_RAW, htons(ETH_P_PAE)) call.

Working Scenario:

Despite the change in protocol to ETH_P_PAE, the overall working scenario of the socket remains consistent.

Socket API

Learning

socket

Create a new socket

bind

Associate the socket with a specific address and port

recv

Receive data from a connected socket.

send

Send data over a connected socket.