Home > database >  Can't properly bind socket unless I pass a seemingly incorrect length
Can't properly bind socket unless I pass a seemingly incorrect length

Time:08-19

The code I've written doesn't work properly unless I pass a seemingly incorrect number to the length argument of bind. It kind of does work; after the accept call I can see it by running netstat, but the port is incorrect. I originally wrote the code in x86 assembly and I then wrote it in C. In both cases, it didn't work.

When calling the function socket, I passed AF_INET (2) as the domain, SOCK_STREAM (1) as the type, and TCP (6) as the protocol.

Here is the code, the one written in C:

#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>

int main(void) {
    unsigned int fd = socket(AF_INET, SOCK_STREAM, 6);
    struct sockaddr_in thing = (struct sockaddr_in) {
        .sin_family = AF_INET, //2 bytes
        .sin_port = 0x2923, //2 bytes
        .sin_addr = 0 //4 bytes
    };

    printf("%zu\n", sizeof thing);

    bind(fd, (struct sockaddr*) &thing, 8); //Using 16 instead of 8 fixes the port problem, why?
    listen(fd, 1);
    accept(fd, 0, 0);
}

To me, 8 looks like the correct length to use. However, 16 seems to be the correct number to use. Why?

Here is the original code written in x86 NASM Assembly:

section .text
global _start

_start:
    push byte 6
    push byte 1
    push byte 2
    mov ecx, esp
    mov ebx, 1              ;socket
    mov eax, 102
    int 80h

    mov edi, eax            ;file descriptor

    push dword 0x00000000   ;4 bytes
    push word 0x2923        ;2 bytes
    push word 2             ;2 bytes
    mov ecx, esp

    push byte 8             ;Length argument, byte turned into 4 bytes in stack
    push ecx
    push edi

    mov ecx, esp
    mov ebx, 2              ;bind
    mov eax, 102
    int 80h

    push byte 1
    push edi
    mov ecx, esp
    mov ebx, 4              ;listen
    mov eax, 102
    int 80h

    push byte 0
    push byte 0 

    push edi

    mov ecx, esp
    mov ebx, 5              ;accept
    mov eax, 102
    int 80h

CodePudding user response:

Look at the examples in the man page: https://man7.org/linux/man-pages/man2/bind.2.html.

You have to pass the size of the sockaddr_in structure.

bind(fd, (struct sockaddr*) &thing, sizeof(thing));

It's very likely that bind makes an internal check, to ensure that the 3rd parameter is indeed the size of the structure in the 2nd parameter

For AF_INET sockets bind surely knows that the 2nd parameter is a sockaddr_in instance, so it knows what value the 3rd parameter must be.

Really, that's nothing mysterious going on here.

CodePudding user response:

bind(fd, (struct sockaddr*) &thing, 8); //Using 16 instead of 8 fixes the port problem, why?

This code will fail with EINVAL (checked with Linux), but this error is simply ignored by your program. This means no explicit bind will be done.

listen(fd, 1);
accept(fd, 0, 0);

Since the explicit bind failed an implicit bind will be done, effectively meaning that the socket will listen on a random address. That's why it does not seem to work. netstat should show the random port here, not the actually intended one.

  • Related