如何在 nasm 中使用 recvfrom 获取 UDP 数据包的源 IP 地址?
How to get source IP address of a UDP packet using recvfrom in nasm?
我正在 nasm 中编写 UDP 套接字,并且我正在使用 recvfrom 系统调用从客户端接收 UDP 数据包。
我可以成功发送消息,但我想向客户发回一个答复。
问题是我无法提取数据包的源IP地址,所以无法使用sendto系统调用。
这是UDP服务器的代码:
%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]
在 network.inc 我有:
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
作为 UDP 客户端,我正在使用 netcat 命令:netcat -u 127.0.0.1 4096
您可以在 SYS_RECVFROM according to the documentation 中传递指向 sockaddr
结构的指针:
mov r8, 0
mov r9, 0
然后通过 sendto
系统调用使用填充结构。
UPD
sockaddr
在 C
中具有以下形状:
struct sockaddr {
unsigned short int sa_family;
char sa_data[14];
};
我想,在 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
我注意到您正在为套接字分配 2 个字节。实际上,套接字必须是 int
:
socket_fd resd 1
接下来:您必须传递给 r9
引用而不是值
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
终于可以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
我正在 nasm 中编写 UDP 套接字,并且我正在使用 recvfrom 系统调用从客户端接收 UDP 数据包。
我可以成功发送消息,但我想向客户发回一个答复。 问题是我无法提取数据包的源IP地址,所以无法使用sendto系统调用。
这是UDP服务器的代码:
%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]
在 network.inc 我有:
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
作为 UDP 客户端,我正在使用 netcat 命令:netcat -u 127.0.0.1 4096
您可以在 SYS_RECVFROM according to the documentation 中传递指向 sockaddr
结构的指针:
mov r8, 0
mov r9, 0
然后通过 sendto
系统调用使用填充结构。
UPD
sockaddr
在 C
中具有以下形状:
struct sockaddr {
unsigned short int sa_family;
char sa_data[14];
};
我想,在 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
我注意到您正在为套接字分配 2 个字节。实际上,套接字必须是 int
:
socket_fd resd 1
接下来:您必须传递给 r9
引用而不是值
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
终于可以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