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.