POSIX Sockets; Deciphering Hostname from sockaddr_in structure - sockets

Is it possible to decipher the hostname given the sockaddr_in strucure?
struct sockaddr_in {
short sin_family; // e.g. AF_INET, AF_INET6
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
struct in_addr {
unsigned long s_addr; // load with inet_pton()
};
I'd tried printing out "udp_server.sin_addr.s_addr" (where udp_server is of type struct sockaddr_in) and it printed me a number.
I believe the s_addr variable is converted to network long? How do I convert it into a readable format so I can determine the host?

There's a number of functions for transforming the number you mentioned (a network address in long format) to human-readable addresses.
Take a look at inet_pton() and inet_ntop() (Presentation to Number, Number to Presentation). Those are AF_INET-specific, and work for both IPv4 and IPv6 if I'm not mistaken.
Suerte!

Yes, it's the IP address in network byte order. Use the inet_ntoa(3) or inet_ntop(3) to get back a string representation of the IP.

Related

NetworkingDriverKit - How can I access packet data?

I've been creating a virtual ethernet interface. I've opened asynchronous communication with a controlling application and every time there are new packets, the controlling app is notified and then asks for the packet data. The packet data is stored in a simple struct, with uint8_t[1600] for the bytes, and uint32_t for the length. The dext is able to populate this struct with dummy data every time a packet is available, with the dummy data visible on the controlling application. However, I'm struggling to fill it with the real packet data.
The IOUserNetworkPacket provides metadata about a packet. It contains a packets timestamp, size, etc, but it doesn't seem to contain the packet's data. There are the GetDataOffset() and GetMemorySegmentOffset() methods which seem to return byte offsets for where the packet data is located in their memory buffer. My instinct tells me to add this offset to the pointer of wherever the packet data is stored. The problem is I have no idea where the packets are actually stored.
I know they are managed by the IOUserNetworkPacketBufferPool, but I don't think that's where their memory is. There is the CopyMemoryDescriptor() method which gives an IOMemoryDescriptor of its contents. I tried using the descriptor to create an IOMemoryMap, using it to call GetAddress(). The pointers to all the mentioned objects lead to junk data.
I must be approaching this entirely wrong. If anyone knows how to access the packet data, or has any ideas, I would appreciate any help. Thanks.
Code snippet within IOUserClient::ExternalMethod:
case GetPacket:
{
IOUserNetworkPacket *packet =
ivars->m_provider->getPacket();
GetPacket_Output output;
output.packet_size = packet->getDataLength();
IOUserNetworkPacketBufferPool *pool;
packet->GetPacketBufferPool(&pool);
IOMemoryDescriptor *memory = nullptr;
pool->CopyMemoryDescriptor(&memory);
IOMemoryMap *map = nullptr;
memory->CreateMapping(0, 0, 0, 0, 0, &map);
uint64_t address = map->GetAddress()
+ packet->getMemorySegmentOffset();
memcpy(output.packet_data,
(void*)address, packet->getDataLength());
in_arguments->structureOutput = OSData::withBytes(
&output, sizeof(GetPacket_Output));
// free stuff
} break;
The problem was caused by an IOUserNetworkPacketBufferPool bug. My bufferSize was set to 1600 except this value was ignored and replaced with 2048. The IOUserNetworkPackets acted as though the bufferSize was 1600 and so they gave an invalid offset.
Creating the buffer pool and mapping it:
kern_return_t
IMPL(FooDriver, Start)
{
// ...
IOUserNetworkPacketBufferPool::Create(this, "FooBuffer",
32, 32, 2048, &ivars->packet_buffer));
packet_buffer->CopyMemoryDescriptor(ivars->packet_buffer_md);
ivars->packet_md->Map(0, 0, 0, IOVMPageSize,
&ivars->packet_buffer_addr, &ivars->packet_buffer_length));
// ...
}
Getting the packet data:
void FooDriver::getPacketData(
IOUserNetworkPacket *packet,
uint8_t *packet_data,
uint32_t *packet_size
) {
uint8_t packet_head;
uint64_t packet_offset;
packet->GetHeadroom(&packet_head);
packet->GetMemorySegmentOffset(&packet_offset);
uint8_t *buffer = (uint8_t*)(ivars->packet_buffer_addr
+ packet_offset + packet_head);
*packet_size = packet->getDataLength();
memcpy(packet_data, buffer, *packet_size);
}

XDP and sk_buff

I started coding in ebpf and XDP.
I am using python bcc to load the XDP program to the NICs.
I am trying to work with __sk_buff structure, but when I am trying to access any filed of skb the verifier failed to load the program.
int xdp_test(struct sk_buff *skb)
{
void *data = (void*)(long)skb->data;
void *data_end = (void*)(long)skb->data_end;
if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) < data_end)
{
struct iphdr * ip = ip_hdr(skb);
// according to my checks, it failed because of this line. I cant access to ip->protocol (or any other fileds)
if (ip->protocol == IPPROTO_TCP)
{
return XDP_PASS;
}
}
...
return XDP_PASS
}
I just want to calculates layer 4 checksum on my program using bpf_l4_csum_replace Which takes skb as the first argument.
Why is that happening?
Can I even use __sk_buff structure in XDP? Or I have to use the xdp_md struct?
UPDATE:
Thanks to Qeole, I understood that I cannot use sk_buff using XDP.
There is a way to calculate TCP checksum using xdp_md?
Indeed you cannot use the struct __sk_buff in XDP programs. You have to use the struct xdp_md instead. XDP performance is due for a great part to the kernel calling the eBPF program before the allocation and initialisation of the socket buffer (struct sk_buff in the kernel), which saves time and resources, but also means you don't have access to that structure in your XDP program.

What exactly is usage of cursor_advance in BPF?

I was looking through a slide by IOvisor project, https://events.static.linuxfound.org/sites/events/files/slides/iovisor-lc-bof-2016.pdf
#include <bcc/proto.h>
struct IPKey { u32 dip; u32 sip; };
BPF_TABLE("hash", struct IPKey, int, mytable, 1024);
int recv_packet(struct __sk_buff *skb) {
struct IPKey key;
u8 *cursor = 0;
struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
key.dip = ip->dst;
key.sip = ip->src;
int *leaf = mytable.lookup(&key);
if (leaf)
*(leaf)++;
return 0;
}
This code is amongst the examples.
I've been using cursor_advance() quite often and now I'm trying to figure out what exactly it does.
I suspect that cursor is a pointer where we save the address of the packet we are parsing.
Then, with cursor_advance() we move the cursor by the size of the ethernet header, since ethernet_t contains all the ethernet header information.
Then, the cursor now at the address at the end of the ethernet header of the packet and if we use variables declared in the ethernet_t header, such as type, like : ethernet->type, we can access the information saved at type since the struct ethernet would read the values saved in that address?
I'm sorry my explanation is not really good.
I'm just looking for a general explanation or if my theory is correct.
Thanks!
Your understanding sounds correct to me. Just think of it as a “cursor” used to successively parse the different headers of your packet. The cursor_advance() macro is defined as:
#define cursor_advance(_cursor, _len) \
({ void *_tmp = _cursor; _cursor += _len; _tmp; })
It adds _len to the _cursor, and returns the value _cursor had before we added _len.
So the first call to cursor_advance() returns the initial value: ethernet points to the beginning of the packet, and we can use its attributes to access the different fields of the Ethernet header. But this same call also moves the cursor forwards by the length of the Ethernet header, so now it points to the beginning of the next header (L3, e.g. IP). The second call to cursor_advance() returns the pointer to the L3 layer, which we store in ip. The cursor is also moved forward and, assuming the packet is IPv4, would now point at the L4 header.
Note: I do not believe this mechanism is widely used in BPF programs aside from the few networking examples available in BCC. Instead, programs often navigate through packet headers with skb->data and skb->data_end.

Broadcast sendto failed

I am trying to broadcast data but the output is udp send failed. I chose a random port 33333. What's wrong with my code?
int main()
{
struct sockaddr_in udpaddr = { sin_family : AF_INET };
int xudpsock_fd,sock,len = 0,ret = 0,optVal = 0;
char buffer[255];
char szSocket[64];
memset(buffer,0x00,sizeof(buffer));
memset(&udpaddr,0,sizeof(udpaddr));
udpaddr.sin_addr.s_addr = INADDR_BROADCAST;
udpaddr.sin_port = htons(33333);
xudpsock_fd = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
optVal = 1;
ret = setsockopt(xudpsock_fd,SOL_SOCKET,SO_BROADCAST,(char*)&optVal,sizeof(optVal));
strcpy(buffer,"this is a test msg");
len = sizeof(buffer);
ret = sendto(xudpsock_fd,buffer,len,0,(struct sockaddr*)&udpaddr,sizeof(udpaddr));
if (ret == -1)
printf("udp send failed\n");
else
printf("udp send succeed\n");
return (0);
}
One problem is that the address family you are trying to send to is zero (AF_UNSPEC). Although you initialize the family to AF_INET at the top of the function, you later zero it out with memset.
On the system I tested with, the send actually works anyway for some strange reason despite the invalid address family, but you should definitely try fixing that first.
You probably had a problem with your default route (eg, you didn't have one). sendto needs to pick an interface to send the packet on, but the destination address was probably outside the Destination/Genmask for each defined interface (see the 'route' command-line tool).
The default route catches this type of packet and sends it through an interface despite this mismatch.
Setting the destination to 127.255.255.255 will usually cause the packet to be sent through the loopback interface (127.0.0.1), meaning it will be able to be read by applications that (in this case) are run on the local machine.

Why does UDT use SOCK_STREAM if it is based on UDP?

Found the following in the example code appserver.cpp distributed with UDT
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
Why would UDT use SOCK_STREAM and not SOCK_DGRAM?
This can be perfectly normal.
If I didn't know anything about UDT, then I would assume that "hints" is likely an instance of addrinfo and used as the second parameter of getaddrinfo()
If the code is just trying to get the IP address of a server (i.e. DNS lookup), then it has to pass something into the hints structure for socktype. Otherwise, the result of getaddrinfo is likely to return 3x the the number of results. One result for SOCK_STREAM, another for SOCK_DGRAM, and a third for SOCK_RAW. But the ai_addr member for each will be the same address.
Now I did just take a peak at the UDT code. Never heard of it until now. But it does appear to have some code that is doing some SOCK_STREAM stuff and using getaddrinfo as a formal way to initialize a sockaddr for subsequent TCP connect.
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
UDTSOCKET fhandle = UDT::socket(hints.ai_family, hints.ai_socktype,hints.ai_protocol);
if (0 != getaddrinfo(argv[1], argv[2], &hints, &peer))
{
cout << "incorrect server/peer address. " << argv[1] << ":" << argv[2] << endl;
return -1;
}
// connect to the server, implict bind
if (UDT::ERROR == UDT::connect(fhandle, peer->ai_addr, peer->ai_addrlen))
But you'll have to ask the UDT developers what it's all about.
UDT is the UDP-based data transfer protocal,so in all it's is just UDP.
check the UDT Manual
link。it says
UDT is connection oriented, for both of its SOCK_STREAM and SOCK_DGRAM mode. connect must be called in order to set up a UDT connection.
so whatever we use,we all have to do a connect() call. so what's the difference?
In SOCK_STREAM,we can use udt's send() API,while in SOCK_DGRAM,we only can use udt's sendmsg() API.
check the manual's "transfer data" and "Messaging with Partial Reliability",i think it may be do a little help.