All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alejandro Colomar <alx@kernel.org>
To: Oliver Crumrine <ozlinuxc@gmail.com>
Cc: linux-kernel@vger.kernel.org, linux-man@vger.kernel.org,
	Peter Seiderer <ps.report@gmx.net>
Subject: Re: [PATCH] ip.7: Add not supported by SOCK_STREAM to socket options
Date: Sun, 17 Mar 2024 19:28:28 +0100	[thread overview]
Message-ID: <Zfc2TFsLwbXbCtym@debian> (raw)
In-Reply-To: <ejhphmjh74ebtk4br3id66f27a4yoh4aukrcz7m6dp7acsu6zr@crtueyadqzmp>

[-- Attachment #1: Type: text/plain, Size: 14375 bytes --]

Hi Oliver,

On Sun, Mar 17, 2024 at 09:55:50AM -0400, Oliver Crumrine wrote:
> It was not made clear in several socket options that they were not
> supported by SOCK_STREAM; this patch fixes that.
> 
> Socket options not supported by SOCK_STREAM are handled in the
> ip_cmsg_recv_offset function in net/ipv4/ip_sockglue.c. The function is
> called for udp sockets, and indirectly by ping and raw sockets, but not
> for STREAM sockets, as they don't support these options.
> 
> Signed-off-by: Oliver Crumrine <ozlinuxc@gmail.com>

Patch applied; thanks.
<https://www.alejandro-colomar.es/src/alx/linux/man-pages/man-pages.git/commit/?h=contrib&id=5675cf3b048ec65b241d51c1130b55420a5d2456>

Have a lovely day!
Alex

> 
> v1->v2: Add IP_RETOPTS to the socket options without support on
> SOCK_STREAM
> 
> Alex, I have attached the two test programs below, updated for support
> with IP_RETOPTS.
> 
> I couldn't get an ip option out of netcat, so I'm attaching the client
> programs, also updated with support for IP_OPTIONS, so they put an ip
> option onto the packet for the server program to recieve.
> 
> Here is the diff between the two servers:
> --- testDgramSocketServer.c     2024-03-17 08:32:27.623451419 -0400
> +++ testStreamSocketServer.c    2024-03-17 08:21:11.860109033 -0400
> @@ -23,7 +23,7 @@
>         struct sockaddr_in local_addr;
>         int s;
> 
> -       s = socket(AF_INET, SOCK_DGRAM, 0);
> +       s = socket(AF_INET, SOCK_STREAM, 0);
>         if (s == -1){
>                 err(1, "error creating socket");
>         }
> @@ -43,8 +43,20 @@
>         if(bind(s, (struct sockaddr*)&local_addr, sizeof(local_addr) ) == -1){
>                 err(1, "error binding to port. try changing it or running as root");
>         }
> +
> +       if(listen(s, 10) == -1){ //10 is the backlog of un-accepted connections. its just an arbitrary number
> +               err(1, "error listening on port");
> +       }
> 
>         while(1){
> +               int connfd = accept(s, (struct sockaddr*)NULL, NULL);
> +               if(connfd == -1){
> +                       err(1, "error accepting connection");
> +               }
> +               if(setsockopt(s, IPPROTO_IP, SOCKOPT, &yes, sizeof(yes)) == -1){ //stream sockets should have this set on the connected socket as well. I left it above for uniformity between the two programs.
> +                       err(1, "error setting socket option");
> +               }
> +
>                 struct msghdr mhdr;
>                 struct iovec iov[1];
>                 struct cmsghdr *cmhdr;
> @@ -63,7 +75,7 @@
>                 memset(databuf, 0, sizeof(databuf));
> 
>                 //this is blocking
> -               int msglen = recvmsg(s, &mhdr, 0);
> +               int msglen = recvmsg(connfd, &mhdr, 0);
>                 if (msglen == -1){
>                         err(1, "recvmsg");
>                 }
> @@ -78,6 +90,7 @@
>                 }
>                 //print out the first byte of data recieved in hex. You can verify this in wireshark if you like.
>                 printf("data read: %sbyte = %02X\n", databuf, tos);
> +               close(connfd);
>         }
> 
>         close(s);
> 
> And the clients in case you're interested:
> --- testDgramSocketClient.c     2024-03-17 08:24:07.640111430 -0400
> +++ testStreamSocketClient.c    2024-03-17 08:23:02.883443865 -0400
> @@ -15,7 +15,7 @@
> 
>         char buf[] = "testing 1 2 3\n";
> 
> -       s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
> +       s = socket(AF_INET, SOCK_STREAM, 0);
>         if(s == -1){
>                 err(1, "error creating socket");
>         }
> @@ -34,7 +34,10 @@
>                 err(1, "error converting network address");
>         }
> 
> -       if(sendto(s, buf, strlen(buf), 0, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){
> +       if(connect(s, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){
> +               err(1, "error connecting");
> +       }
> +       if(send(s, buf, strlen(buf), 0) == -1){
>                 err(1, "error sending data");
>         }
> 
> ---
>  man7/ip.7 | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/man7/ip.7 b/man7/ip.7
> index 2b4b06324..39055d3cf 100644
> --- a/man7/ip.7
> +++ b/man7/ip.7
> @@ -828,6 +828,9 @@ is not zero, the primary local address of the interface specified by the
>  index overwrites
>  .I ipi_spec_dst
>  for the routing table lookup.
> +Not supported for
> +.B SOCK_STREAM
> +sockets.
>  .TP
>  .BR IP_RECVERR " (since Linux 2.2)"
>  .\" Precisely: since Linux 2.1.15
> @@ -989,6 +992,9 @@ in which the kernel returns the original destination address
>  of the datagram being received.
>  The ancillary message contains a
>  .IR "struct sockaddr_in" .
> +Not supported for
> +.B SOCK_STREAM
> +sockets.
>  .TP
>  .BR IP_RECVTOS " (since Linux 2.2)"
>  .\" Precisely: since Linux 2.1.68
> @@ -998,6 +1004,9 @@ ancillary message is passed with incoming packets.
>  It contains a byte which specifies the Type of Service/Precedence
>  field of the packet header.
>  Expects a boolean integer flag.
> +Not supported for
> +.B SOCK_STREAM
> +sockets.
>  .TP
>  .BR IP_RECVTTL " (since Linux 2.2)"
>  .\" Precisely: since Linux 2.1.68
> @@ -1015,6 +1024,9 @@ Identical to
>  .BR IP_RECVOPTS ,
>  but returns raw unprocessed options with timestamp and route record
>  options not filled in for this hop.
> +Not supported for
> +.B SOCK_STREAM
> +sockets.
>  .TP
>  .BR IP_ROUTER_ALERT " (since Linux 2.2)"
>  .\" Precisely: since Linux 2.1.68
> -- 
> 2.44.0
> 

> #include <stdio.h>
> #include <err.h>
> #include <string.h>
> #include <stdlib.h>
> #include <arpa/inet.h>
> #include <sys/socket.h>
> #include <unistd.h>
> 
> #define PORT 8888 //The port on which to send data
> #define ADDR "127.0.0.1" //The internet address to send packets to
> 
> int main(void){
> 	int s;
> 	struct sockaddr_in server_addr;
> 
> 	char buf[] = "testing 1 2 3\n";
> 
> 	s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
> 	if(s == -1){
> 		err(1, "error creating socket");
> 	}
> 
> 	uint8_t options = 1; //noop in the language of ip options
> 
> 	if(setsockopt(s, IPPROTO_IP, IP_OPTIONS, &options, 1) == -1){
> 		err(1, "error setting socket options");
> 	}
> 
> 	memset(&server_addr, 0, sizeof(server_addr));
> 	
> 	server_addr.sin_family = AF_INET;
> 	server_addr.sin_port = htons(PORT);
> 	if(inet_pton(AF_INET, ADDR, &server_addr.sin_addr) != 1){ // I realize I'm checking the return value differently here. If you read the man page for inet_pton, it'll make sense.
> 		err(1, "error converting network address");
> 	}
> 
> 	if(sendto(s, buf, strlen(buf), 0, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){
> 		err(1, "error sending data");
> 	}
> 	
> 	close(s);
> }

> #include<stdio.h>
> #include<err.h>
> #include<string.h>
> #include<stdlib.h>
> #include<arpa/inet.h>
> #include<sys/socket.h>
> #include<unistd.h>
> 
> #define PORT 8888	//The port on which to listen for incoming data
> 
> 
> //Hi Alex,
> //These are the two lines that allow you to switch between the three socket options outlined in my patch
> //The socket options tell the kernel to add a control message (cmsg), allowing the program
> //to recieve the data it is requesting. The three options are: IP_RECVTOS for the type of service byte,
> //IP_RECVORIGDSTADDR for the orignial dst address, and IP_PKTINFO for some random packet info, and IP_RETOPTS
> //for some random ip packet options
> #define SOCKOPT IP_RECVORIGDSTADDR
> //This field is synonymous with the above one. Valid options are: IP_TOS, IP_ORIGDSTADDR, IP_PKTINFO, and IP_OPTIONS
> #define RECIVEOPTION IP_ORIGDSTADDR
> 
> int main(void){
> 	struct sockaddr_in local_addr;
> 	int s;
> 	
> 	s = socket(AF_INET, SOCK_DGRAM, 0);
> 	if (s == -1){
> 		err(1, "error creating socket");
> 	}
> 	
> 	memset(&local_addr, 0, sizeof(local_addr));
> 	
> 	local_addr.sin_family = AF_INET;
> 	local_addr.sin_port = htons(PORT);
> 	local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
> 
> 	int yes = 1;
> 	if(setsockopt(s, IPPROTO_IP, SOCKOPT, &yes, sizeof(yes)) == -1){
> 		err(1, "error setting socket option");
> 	}
> 
> 
> 	if(bind(s, (struct sockaddr*)&local_addr, sizeof(local_addr) ) == -1){
> 		err(1, "error binding to port. try changing it or running as root");
> 	}
> 
> 	while(1){
> 		struct msghdr mhdr;
> 		struct iovec iov[1];
> 		struct cmsghdr *cmhdr;
> 		char control[1000];
> 		char databuf[BUFSIZ];
> 		unsigned char tos = 0;
> 
> 		mhdr.msg_name = &local_addr;
> 		mhdr.msg_namelen = sizeof(local_addr);
> 		mhdr.msg_iov = iov;
> 		mhdr.msg_iovlen = 1;
> 		mhdr.msg_control = &control;
> 		mhdr.msg_controllen = sizeof(control);
> 		iov[0].iov_base = databuf;
> 		iov[0].iov_len = sizeof(databuf);
> 		memset(databuf, 0, sizeof(databuf));	
> 		
> 		//this is blocking
> 		int msglen = recvmsg(s, &mhdr, 0);
> 		if (msglen == -1){
> 			err(1, "recvmsg");
> 		}
> 		cmhdr = CMSG_FIRSTHDR(&mhdr);
> 		while (cmhdr) {
> 			printf("cmsg recieved\n");
> 			if (cmhdr->cmsg_level == IPPROTO_IP && cmhdr->cmsg_type == RECIVEOPTION) {
> 				//read the byte recieved
> 				tos = ((unsigned char *)CMSG_DATA(cmhdr))[0];
> 			}
> 			cmhdr = CMSG_NXTHDR(&mhdr, cmhdr);
> 		}
> 		//print out the first byte of data recieved in hex. You can verify this in wireshark if you like.
> 		printf("data read: %sbyte = %02X\n", databuf, tos);
> 	}
> 
> 	close(s);
> 	return 0;
> }

> #include <stdio.h>
> #include <err.h>
> #include <string.h>
> #include <stdlib.h>
> #include <arpa/inet.h>
> #include <sys/socket.h>
> #include <unistd.h>
> 
> #define PORT 8888 //The port on which to send data
> #define ADDR "127.0.0.1" //The internet address to send packets to
> 
> int main(void){
> 	int s;
> 	struct sockaddr_in server_addr;
> 
> 	char buf[] = "testing 1 2 3\n";
> 
> 	s = socket(AF_INET, SOCK_STREAM, 0);
> 	if(s == -1){
> 		err(1, "error creating socket");
> 	}
> 
> 	uint8_t options = 1; //noop in the language of ip options
> 
> 	if(setsockopt(s, IPPROTO_IP, IP_OPTIONS, &options, 1) == -1){
> 		err(1, "error setting socket options");
> 	}
> 
> 	memset(&server_addr, 0, sizeof(server_addr));
> 	
> 	server_addr.sin_family = AF_INET;
> 	server_addr.sin_port = htons(PORT);
> 	if(inet_pton(AF_INET, ADDR, &server_addr.sin_addr) != 1){ // I realize I'm checking the return value differently here. If you read the man page for inet_pton, it'll make sense.
> 		err(1, "error converting network address");
> 	}
> 
> 	if(connect(s, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){
> 		err(1, "error connecting");
> 	}
> 	if(send(s, buf, strlen(buf), 0) == -1){
> 		err(1, "error sending data");
> 	}
> 	
> 	close(s);
> }

> #include<stdio.h>
> #include<err.h>
> #include<string.h>
> #include<stdlib.h>
> #include<arpa/inet.h>
> #include<sys/socket.h>
> #include<unistd.h>
> 
> #define PORT 8888	//The port on which to listen for incoming data
> 
> 
> //Hi Alex,
> //These are the two lines that allow you to switch between the three socket options outlined in my patch
> //The socket options tell the kernel to add a control message (cmsg), allowing the program
> //to recieve the data it is requesting. The three options are: IP_RECVTOS for the type of service byte,
> //IP_RECVORIGDSTADDR for the orignial dst address, and IP_PKTINFO for some random packet info, and IP_RETOPTS
> //for some random ip packet options
> #define SOCKOPT IP_RECVORIGDSTADDR
> //This field is synonymous with the above one. Valid options are: IP_TOS, IP_ORIGDSTADDR, IP_PKTINFO, and IP_OPTIONS
> #define RECIVEOPTION IP_ORIGDSTADDR
> 
> int main(void){
> 	struct sockaddr_in local_addr;
> 	int s;
> 	
> 	s = socket(AF_INET, SOCK_STREAM, 0);
> 	if (s == -1){
> 		err(1, "error creating socket");
> 	}
> 	
> 	memset(&local_addr, 0, sizeof(local_addr));
> 	
> 	local_addr.sin_family = AF_INET;
> 	local_addr.sin_port = htons(PORT);
> 	local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
> 
> 	int yes = 1;
> 	if(setsockopt(s, IPPROTO_IP, SOCKOPT, &yes, sizeof(yes)) == -1){
> 		err(1, "error setting socket option");
> 	}
> 
> 
> 	if(bind(s, (struct sockaddr*)&local_addr, sizeof(local_addr) ) == -1){
> 		err(1, "error binding to port. try changing it or running as root");
> 	}
> 	
> 	if(listen(s, 10) == -1){ //10 is the backlog of un-accepted connections. its just an arbitrary number
> 		err(1, "error listening on port");
> 	}
> 
> 	while(1){
> 		int connfd = accept(s, (struct sockaddr*)NULL, NULL);
> 		if(connfd == -1){
> 			err(1, "error accepting connection");
> 		}
> 		if(setsockopt(s, IPPROTO_IP, SOCKOPT, &yes, sizeof(yes)) == -1){ //stream sockets should have this set on the connected socket as well. I left it above for uniformity between the two programs.
> 			err(1, "error setting socket option");
> 		}
> 	
> 		struct msghdr mhdr;
> 		struct iovec iov[1];
> 		struct cmsghdr *cmhdr;
> 		char control[1000];
> 		char databuf[BUFSIZ];
> 		unsigned char tos = 0;
> 
> 		mhdr.msg_name = &local_addr;
> 		mhdr.msg_namelen = sizeof(local_addr);
> 		mhdr.msg_iov = iov;
> 		mhdr.msg_iovlen = 1;
> 		mhdr.msg_control = &control;
> 		mhdr.msg_controllen = sizeof(control);
> 		iov[0].iov_base = databuf;
> 		iov[0].iov_len = sizeof(databuf);
> 		memset(databuf, 0, sizeof(databuf));	
> 		
> 		//this is blocking
> 		int msglen = recvmsg(connfd, &mhdr, 0);
> 		if (msglen == -1){
> 			err(1, "recvmsg");
> 		}
> 		cmhdr = CMSG_FIRSTHDR(&mhdr);
> 		while (cmhdr) {
> 			printf("cmsg recieved\n");
> 			if (cmhdr->cmsg_level == IPPROTO_IP && cmhdr->cmsg_type == RECIVEOPTION) {
> 				//read the byte recieved
> 				tos = ((unsigned char *)CMSG_DATA(cmhdr))[0];
> 			}
> 			cmhdr = CMSG_NXTHDR(&mhdr, cmhdr);
> 		}
> 		//print out the first byte of data recieved in hex. You can verify this in wireshark if you like.
> 		printf("data read: %sbyte = %02X\n", databuf, tos);
> 		close(connfd);
> 	}
> 
> 	close(s);
> 	return 0;
> }


-- 
<https://www.alejandro-colomar.es/>
Looking for a remote C programming job at the moment.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

  reply	other threads:[~2024-03-17 18:28 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-17 13:55 [PATCH] ip.7: Add not supported by SOCK_STREAM to socket options Oliver Crumrine
2024-03-17 18:28 ` Alejandro Colomar [this message]
  -- strict thread matches above, loose matches on Subject: below --
2024-03-02 18:19 Oliver Crumrine
2024-03-04 16:15 ` Alejandro Colomar
2024-03-05 19:31   ` Oliver Crumrine
2024-03-06 10:50     ` Alejandro Colomar
2024-03-06 10:58     ` Alejandro Colomar
2024-03-06 13:02       ` Oliver Crumrine
2024-03-06 13:12         ` Alejandro Colomar
     [not found]           ` <CAK1VsR3MsyphK+=rA7XcEigiSd6J_-QsVW+8hH1fU9xmRY3nGQ@mail.gmail.com>
2024-03-13 18:27             ` Oliver Crumrine
2024-03-13 22:35               ` Alejandro Colomar
2024-03-16 19:33               ` Alejandro Colomar
2024-03-16 18:41                 ` Oliver Crumrine
2024-03-17  2:02                   ` Alejandro Colomar
2024-03-17  9:02                     ` Oliver Crumrine
2024-03-17 13:55                       ` Alejandro Colomar
     [not found]                         ` <hxkixsi6uymkjmt4ughda2xmh6guzcaccrjbvsuasndyuvq5rz@36oqfaepfiql>
2024-03-17 15:17                           ` Alejandro Colomar
2024-03-17 11:31           ` Peter Seiderer
2024-03-17 18:27             ` Alejandro Colomar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Zfc2TFsLwbXbCtym@debian \
    --to=alx@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-man@vger.kernel.org \
    --cc=ozlinuxc@gmail.com \
    --cc=ps.report@gmx.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.