Raw Socket recvfrom not working for TCP

Hello, I have created raw socket as below

rawSockfd = socket(AF_INET,SOCK_RAW,IPPROTO_IP)

Added flag 5 sec SO_RCVTIMEO, IP_HDRINCL to 1 via setsockopt.

Sending IP Packet as below:

struct sockaddr_in connection = getSockAddr(dstIPAddress);
 long bytes = sendto(rawSockfd, (uint8_t *)packet, size, 0, (struct sockaddr *)&connection, sizeof(struct sockaddr));

I am trying to receive as below:

long rsize = recvfrom(rawSock, buffer, size, 0, (struct sockaddr *)&connection, (socklen_t *)&addrlen);

This works fine for ICMP, UDP. recvfrom able to read packet back.

We are facing issue during TCP. recvfrom returns error: Resource temporarily unavailable after 5 sec timeout. If we remove timeout flag SO_RCVTIMEO then it gets stuck forever.

TCPdump shows following logs on destination. Instead of SYN ACK it's getting Reset:

09:21:03.972632 IP 10.215.179.1.54745 > 10.207.134.154.8181: Flags [SEW], seq 358899317, win 65535, options [mss 1380,nop,wscale 6,nop,nop,TS val 426499980 ecr 0,sackOK,eol], length 0

09:21:03.972755 IP 10.207.134.154.8181 > 10.215.179.1.54745: Flags [R.], seq 0, ack 358899318, win 0, length 0

is this something macOS not sending TCP response back to rawsocket or something is wrong in my code?

Accepted Reply

Raw Socket recvfrom not working for TCP

This is not going to work on any BSD Sockets implementation. You can’t use raw sockets to read TCP or UDP. To quote my trusty (and dusty, literally!) copy of Stevens [1]:

The following rules apply;

  1. Received UDP packets and received TCP packets are never [their emphasis] passed to a raw socket.

This is UNIX Network Programming, Volume 1, Second Edition, section 25.4 Raw Socket Input, page 659.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] http://www.unpbook.com

Replies

Raw Socket recvfrom not working for TCP

This is not going to work on any BSD Sockets implementation. You can’t use raw sockets to read TCP or UDP. To quote my trusty (and dusty, literally!) copy of Stevens [1]:

The following rules apply;

  1. Received UDP packets and received TCP packets are never [their emphasis] passed to a raw socket.

This is UNIX Network Programming, Volume 1, Second Edition, section 25.4 Raw Socket Input, page 659.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] http://www.unpbook.com

Hi @eskimo, This book is really helpful. Thank you.

There is one more point under Raw Socket Input:

  • All IP datagrams with a protocol field that the kernel does not understand are passed to a raw socket. The only kernel processing done on these packets is the minimal verification of some IP header fields: the IP version, IPv4 header checksum, header length, and destination IP address (pp. 213–220 of TCPv2).

is there any workaround that we can do with ip packet during sendto so that kernel does not understand and passes to raw socket?

is there any workaround that we can do with ip packet during sendto so that kernel does not understand and passes to raw socket?

I’m not sure what you’re asking for here. Can you take a step back and explain your high-level goal?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Can you take a step back and explain your high-level goal?

I am getting NEPacket via Packet tunnel provider System extension. I need to forward this packet to server Which will re-injected this ip packet into network stack after processing. Since raw socket can't be opened by system extension due to sandbox restriction, i am reading IP packet in separate process via BSD Packet Filter(BPF) - read(bpf, bpfBuffer, bufLength);

After receiving IP Packet at the bpf end, I am using raw socket to send it to server. sendto is working fine, its getting receive at server end. recvfrom is failing. For ICMP, both sendto and recvfrom is working fine.

Please let me know if any other ways to achieve this?

FYI Following code working fine on linux, but not working on mac.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(void) {
  int i, recv_length, sockfd;

  u_char buffer[9000];

  printf("Opening socket\n");
  if ((sockfd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) == -1) {
    printf("Socket failed!!\n");

    return -1;
  }
  printf("Socket opened\n");

  for(i=0; i < 3; i++) {
   printf("Going to read i: %d\n", i);
   recv_length = recv(sockfd, buffer, 8000, 0);
   printf("Got some bytes : %d\n", recv_length);
  }

  return 0;
}

Following code working fine on linux

It’s called BSD Sockets for a reason (-:

Please let me know if any other ways to achieve this?

Nothing good springs to mind.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"