I'm writing a UDP socket in nasm and I'm using the recvfrom system call to receive a UDP packet from a client.
I can successfully get the message sent, but I would like to send back to the client an answer. The problem is that I can't extract the source IP address of the packet, so I can't use the sendto system call.
This is the code of the UDP server:
%include "../StandardLibrary/standardlib.inc"
%include "./network.inc"
PORT_NUMBER equ 4096
%macro printError 3
print %1
printLineInt %2, %3
%endmacro
%macro clearBuffer 1
getLength %1
mov r12, 0
%%loop:
mov [%1 + r12], byte 0
inc r12
cmp r11, r12
jne %%loop
%endmacro
section .data
sock_addr:
istruc sockaddr_in
at sockaddr_in.sin_family, dw AF_INET
at sockaddr_in.sin_port, dw htons(PORT_NUMBER)
at sockaddr_in.in_addr, db 00h, 00h, 00h, 00h
at sockaddr_in.sin_zero, db 0, 0, 0, 0, 0, 0, 0, 0
iend
client_sockaddr:
istruc sockaddr
at sockaddr.sa_family, dw AF_INET
at sockaddr.sa_data, db 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0
iend
;Messaggi di successo
so_creation_success db "Socket creato con successo", 0
so_binding_success db "Binding del socket eseguito con successo", 0
so_started_capturing db "Socket in ascolto di messaggi...", 0
;Messaggi di errore
so_creation_error db "Errore nella creazione del socket: ", 0
so_binding_error db "Errore nel binding del socket: ", 0
so_capture_error db "Errore nella ricezione del messaggio: ", 0
so_sending_error db "Errore nell'invio del messaggio: ", 0
section .bss
buffer resb 100
socket_fd resw 1
error_code resq 1
tmp resb 10
section .text
global _start
_start:
;1) Creazione del socket
mov rax, SYS_SOCKET
mov rdi, AF_INET
mov rsi, SOCK_DGRAM
mov rdx, 0
syscall
cmp rax, -1
jle _socket_error
;Carica nello stack il file descriptor
mov [socket_fd], rax
printLine so_creation_success
;2) Binding del socket
mov rax, SYS_BIND
mov rdi, [socket_fd]
mov rsi, sock_addr
mov rdx, sockaddr_in_size
syscall
cmp rax, -1
jle _binding_error
printLine so_binding_success
;3) Ricezione dei messaggi
_listen:
mov rax, SYS_RECVFROM
mov rdi, [socket_fd]
mov rsi, buffer
mov rdx, 20
mov r10, 0
mov r8, client_sockaddr
mov r9, 16
syscall
cmp rax, -1 ;Controlla che non ci siano stati errori
jle _capture_error
cmp rax, 1 ;Controlla che non sia stato ricevuto un pcchetto vuoto
jle _exit ;è definito vuoto anche un pacchetto con un solo carattere
;Messaggio ricevuto con successo
print buffer
clearBuffer buffer ;Svuota il buffer
jmp _listen
;Il programma è terminato con successo
_exit:
exit
;Errore nella creazione del socket
_socket_error:
neg rax
mov [error_code], rax
printError so_creation_error, [error_code], tmp
exit [error_code]
;Errore durante il binding del socket
_binding_error:
neg rax
mov [error_code], rax
printError so_binding_error, [error_code], tmp
exit [error_code]
;Errore durante la ricezione del messaggio
_capture_error:
neg rax
mov [error_code], rax
printError so_capture_error, [error_code], tmp
exit [error_code]
And on network.inc I have:
SYS_SOCKET equ 41 ;Id system call per la creazione del socket
SYS_SENDTO equ 44 ;Id system call per l'invio di datagram UDP
SYS_RECVFROM equ 45 ;Id system call per la ricezione di datagram UDP
SYS_BIND equ 49 ;Id system call per legare un socket ad un indirizzo IP (o ad una famiglia)
AF_INET equ 2 ;Rete IPv4
SOCK_DGRAM equ 2 ;Id del protocollo UDP
INADDR_ANY equ 0 ;Indica che il socket accetta comunicazioni da qualsiasi indirizzo IP
;Traduce x in un valore di tipo network byte order
%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)
;Rappresenta un indirizzo IPv4
struc in_addr
.s_addr: resb 4 ;Valore dei 4 ottetti
endstruc
;Rappresenta la struttura di un socket
struc sockaddr_in
.sin_family: resw 1 ;Id del tipo di indirizzo
.sin_port: resw 1 ;Numero di porta
.in_addr: resb 4 ;Indirizzo IP
.sin_zero: resb 8 ;Byte di rimepimento
endstruc
struc sockaddr
.sa_family resw 1
.sa_data resb 14
endstruc
As UDP client I'm using the netcat command: netcat -u 127.0.0.1 4096
You can pass a pointer to your sockaddr
structure in SYS_RECVFROM according to the documentation here:
mov r8, 0
mov r9, 0
And then use filled structure with sendto
syscall.
UPD
sockaddr
has following shape in C
:
struct sockaddr {
unsigned short int sa_family;
char sa_data[14];
};
I think, it looks something like this in NASM:
struc sockaddr
.sa_family resw 1
.sa_data db 14
endstruc
client_sock_addr:
istruc sockaddr
at sockaddr.sa_family, dw AF_INET
at sockaddr.sa_data, db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
iend
UPD #2
I've noticed that you're allocating 2 bytes for the socket. Actually, sockets must be int
:
socket_fd resd 1
Next thing: you have to pass to r9
reference rather than value
section .data
; ...
client_sockaddr_len dd 16
; ...
; ...
mov rax, SYS_RECVFROM
mov rdi, [socket_fd]
mov rsi, buffer
mov rdx, 20
mov r10, 0
mov r8, client_sockaddr
mov r9, client_sockaddr_len
syscall
And finally you can sendto
mov rax, SYS_SENDTO
mov rdi, [socket_fd]
mov rsi, buffer
mov rdx, 50
mov r10, 0
mov r8, client_sockaddr
mov r9, [client_sockaddr_len]
syscall