sockets - 如何在 nasm 中使用 recvfrom 获取 UDP 数据包的源 IP 地址?
问题描述
我正在用 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
解决方案
您可以根据此处的文档sockaddr
将指针传递给SYS_RECVFROM 中的结构:
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
推荐阅读
- java - 在二维数组中查找重复项
- ajax - 从 FormSubmit API 发送电子邮件
- python - 后端 API 获取在 npm start (json) 上工作,但在 netlify 上使用 npm build 时转换为 html
- c# - Blazor 服务器应用程序的 Razor 页面中的异步 Lamblda 表达式
- python - 我可以从列表中排除一个项目,但不能从列表本身中删除它吗?
- gdb - 在调试时传递一个尖括号作为命令行参数输入
- xml - XSLT - 提取具有目标属性值和元素值的子元素的节点的属性值?
- python - 如何在 Python 中处理不受信任的证书 Selenium Webdriver?
- excel - 为什么我的 ActiveCell.FormulaR1C1 使用 RC 相对引用打印了错误的值?
- laravel - 我发现此错误: Illuminate\Routing\Exceptions\UrlGenerationException Missing required parameters for [Route: Product.update]