Re: [PATCH] ip.7: Add not supported by SOCK_STREAM to socket options

From: Oliver Crumrine
Date: Sat Mar 16 2024 - 18:41:38 EST


On Sat, Mar 16, 2024 at 08:33:36PM +0100, Alejandro Colomar wrote:
> Hi Oliver,
>
> On Wed, Mar 13, 2024 at 02:27:17PM -0400, Oliver Crumrine wrote:
> > > Hi Alex,
> > > I apologize for your repeated troubles with my test program.
> > > I have attached a video of myself using it in the method that I
> > > described to you. (I emailed you off-list as to avoid sending a 12
> > > MB video to the whole list)
> > >
> > > If you are using it in the same way that works for me, I don't know
> > > what the problem is. If I could've been clearer in my instructions, let
> > > me know for the future.
> > >
> > > Thanks,
> > > Oliver
> >
> > Hi Alex,
> > Were you able to make any progress whatsoever with this test program?
>
> I'm sorry, but I haven't been able to reproduce the behavior. The test
> programs have several problems which I reported in previous mails.
> Maybe there's something that makes it unstable and in your system
> behaves differently? Please clean up those examples, and try to run
> them in a different system, and maybe then I can reproduce it.
>
> Have a lovely day!
> Alex
>
>
> $ uname -a
> Linux debian 6.8.0-rc7-alx-dirty #3 SMP PREEMPT_DYNAMIC Mon Mar 4 15:24:33 CET 2024 x86_64 GNU/Linux
>
> --
> <https://www.alejandro-colomar.es/>
Hi Alex,
I have cleaned up my test programs. I have also tested them on other
systems (including on systems which I had installed the rc7 kernel
onto). In the very slight chance that your netcat isn't working, (very
narrow chances, but still there), I have attached client programs to go
along with the servers.
Thanks,
Oliver

#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;

int send_len;
char buf[] = "testing 1 2 3\n";

s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(s == -1){
err(1, "error creating socket");
}

memset((char*)&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.
#define SOCKOPT IP_RECVORIGDSTADDR
//This field is synonymous with the above one. Valid options are: IP_TOS, IP_ORIGDSTADDR, and IP_PKTINFO
#define RECIVEOPTION IP_ORIGDSTADDR

int main(void){
struct sockaddr_in local_addr;

int s;
int recv_len;
char buf[BUFSIZ];

s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == -1){
err(1, "error creating socket");
}

memset((char *) &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[1500];
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
if ((recv_len = recvmsg(s, &mhdr, 0)) == -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;

int send_len;
char buf[] = "testing 1 2 3\n";

s = socket(AF_INET, SOCK_STREAM, 0);
if(s == -1){
err(1, "error creating socket");
}

memset((char*)&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.
#define SOCKOPT IP_RECVORIGDSTADDR
//This field is synonymous with the above one. Valid options are: IP_TOS, IP_ORIGDSTADDR, and IP_PKTINFO
#define RECIVEOPTION IP_ORIGDSTADDR

int main(void){
struct sockaddr_in local_addr;

int s;
int recv_len;
char buf[BUFSIZ];

s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1){
err(1, "error creating socket");
}

memset((char *) &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[1500];
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
if ((recv_len = recvmsg(connfd, &mhdr, 0)) == -1){
err(1, "recvmsg\n");
}
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;
}