Create a SOCK_RAW socket only to send data without any recvform ()

If I create a socket of type SOCK_RAW only to send some data without receiving any data, is there a problem when the kernel continues to receive network packets and copies its datagram to somebuffer (applications?). In other words, after some kind of buffer is full, what will happen? mistake or ignore?

I do not know how to prevent the kernel from delivering a copy of the datagram to my application.

Link http://sock-raw.org/papers/sock_raw 0x4 raw_input

After the IP-level processes a new incoming IP-datagram, it calls ip_local_deliver_finish () the kernel function which is responsible for calling the registered transport handler by checking the protocol field of the IP header (remember that above). However, before it delivers the datagram to the handler, it checks each time if the application created a raw socket with the same protocol number. If here is one or more of these applications, it makes a copy of the datagram and delivers it to them as well.

+6
source share
2 answers

You can use shutdown (2) to disable the socket receptor. See the desktop close page

EDIT: I found that shutdown only works on connected (i.e. TCP) sockets. There are two possibilities with Raw socket:

  • Get data in a temporary buffer (with recv ) and discard it (possibly in another thread)
  • If I remember well when the socket buffer is full, incoming data is automatically discarded (and the data in the buffer does not change), so you can set the size of the socket receive buffer to 0 (and increase it later, if necessary).

Here's how to set the size of the receive buffer to 0:

int opt = 0; setsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)); 

TEST

 /** * @file raw_print_pkt.c * @brief * @author Airead Fan < fgh1987168@gmail.com > * @date 2012/08/22 12:35:22 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/ioctl.h> #include <netinet/ip.h> #include <netinet/tcp.h> int main(int argc, char *argv[]) { int s; ssize_t rn; /* receive number */ struct sockaddr_in saddr; char packet[4096]; int count; if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) { perror("error:"); exit(EXIT_FAILURE); } memset(packet, 0, sizeof(packet)); socklen_t *len = (socklen_t *)sizeof(saddr); int fromlen = sizeof(saddr); int opt = 0; count = 0; while(1) { if ((rn = recvfrom(s, (char *)&packet, sizeof(packet), 0, (struct sockaddr *)&saddr, &fromlen)) < 0) perror("packet receive error:"); if (rn == 0) { printf("the peer has performed an orderly shutdown\n"); break; } printf("[%d] rn = %lu \n", count++, rn); if (count == 16) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { perror("setsocketopt failed"); } else { fprintf(stdout, "setsocketopt successful\n"); } // int shutdown(int sockfd, int how); /* if (shutdown(s, SHUT_RD) < 0) { * perror("shutdown failed"); * } */ } } return 0; } 

TEST 2 (the same):

 int main(int argc, char *argv[]) { int s; ssize_t rn; /* receive number */ char packet[4096]; int count; if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) { perror("error:"); exit(EXIT_FAILURE); } memset(packet, 0, sizeof(packet)); int opt = 0; count = 0; //Set recv buffer size if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { perror("setsocketopt failed"); } else { fprintf(stdout, "setsocketopt successful\n"); } //10 seconds countdown int i = 10; while(i > 0) { printf("\r%d ", i); fflush(stdout); i--; sleep(1); } printf("\n"); while(1) { if ((rn = recv(s, (char *)&packet, sizeof(packet), 0)) <= 0) perror("packet receive error:"); printf("[%d] rn = %lu \n", count++, rn); } return 0; } 

Here's how to continue test 2:

First of all, set the buffer size to 4096 (or more if you have a lot of traffic on your network). Compilation and launch. 10 seconds before receiving data, send a lot of data to the socket. After 10 seconds, the program will receive everything that you sent during the countdown.

After that, set the buffer size to 0. Continue as before. After 10 seconds, the program will not receive data sent during the countdown. But if you send data to recvfrom , they will read it normally.

+4
source

I really don't understand what you want! if you want to just enter some packages, it's simple:

 #include<netinet/tcp.h> /* TCP header */ #include<netinet/ip.h> /* IP header */ /* Checksum compute function */ /* source : http://www.winpcap.org/pipermail/winpcap-users/2007-July/001984.html */ unsigned short checksum(unsigned short *buffer, int size) { unsigned long cksum=0; while(size >1) { cksum+=*buffer++; size -=sizeof(unsigned short); } if(size) cksum += *(UCHAR*)buffer; cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (unsigned short)(~cksum); } int main (int argc, char **argv) { char packet_buffer[BUFFER_SIZE]; struct sockaddr_in sin; struct iphdr *ip_header; /* IP header */ struct tcphdr *tcp_header; /* TCP header */ int flag = 1; /* Creating RAW socket */ int raw_socket = socket (PF_INET, SOCK_RAW, IPPROTO_TCP); ip_header = (struct iphdr *) packet_buffer; tcp_header = (struct tcphdr *) (packet_buffer + sizeof (struct ip)); sin.sin_family = AF_INET; sin.sin_port = htons(PORT_NUMBER); sin.sin_addr.s_addr = inet_addr (IP_ADDRESS); /* Zeroing the bbuffer */ memset (packet_buffer, 0, BUFFER_SIZE); /* Construct your IP Header */ ip_header->ihl = 5; ip_header->version = 4; ip_header->tos = 0; ip_header->tot_len = sizeof (struct ip) + sizeof (struct tcphdr); ip_header->id = htonl(CHOOSE_PACKET_ID); ip_header->frag_off = 0; ip_header->ttl = 255; ip_header->protocol = 6; /* TCP. Change to 17 if you want UDP */ ip_header->check = 0; ip_header->saddr = inet_addr (SOURCE_IP_ADDRESS_TO_SPOOF); ip_header->daddr = sin.sin_addr.s_addr; /* Construct your TCP Header */ tcp_header->source = htons (SOURCE); tcp_header->dest = htons(DEST); tcp_header->seq = random(); tcp_header->ack_seq = 0; tcp_header->doff = 0; tcp_header->syn = 1; tcp_header->window = htonl(65535); tcp_header->check = 0; tcp_header->urg_ptr = 0; /* IP Checksum */ ip_header->check = checksum((unsigned short *) packet_buffer, ip_header->tot_len >> 1); if (setsockopt(raw_socket, IPPROTO_IP, IP_HDRINCL, &flag, sizeof(flag)) < 0) { /* ERROR handling */ } while (1) { /* Send the packet */ if (sendto(raw_socket, packet_buffer, ip_header->tot_len, 0, (struct sockaddr *) &sin, sizeof (sin)) < 0) { /* ERROR handling */ } /* The rest of your need */ } return 0; } 
+2
source

Source: https://habr.com/ru/post/923442/


All Articles