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@xxxxxxxxx> 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:
signature.asc
Description: PGP signature