当前位置: 首页 > 知识库问答 >
问题:

如何在nasm中使用recvfrom获取UDP数据包的源IP地址?

班思源
2023-03-14

我正在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-u127.0。零点一四零九六

共有1个答案

查锦程
2023-03-14

您可以根据这里的留档在SYS_RECVFROM中传递一个指针到您的ockaddr结构:

mov r8, 0
mov r9, 0

然后将填充结构与sendtosyscall一起使用。

UPD

sockaddrC中具有以下形状:

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
 类似资料:
  • 问题内容: 我想获取计算机的IP地址。我使用了下面的代码,但是返回了。 我想获取IP地址(例如),而不是回送地址。 问题答案: 您需要遍历所有网络接口 播放(取自util / helper.go)

  • 问题内容: 我不是指 127.0.0.1 而是其他计算机将用来访问该计算机的计算机,例如 192.168.1.6 问题答案: http://nodejs.org/api/os.html#os_os_networkinterfaces

  • 问题内容: 如何在Django中获取用户的IP? 我有这样的看法: 但是我得到这个错误: 问题答案: 确保正确配置了反向代理(如果有)(例如,为Apache安装)。 注意:上面使用的第一项,但是你可能想使用最后一项(例如,在Heroku的情况下:在Heroku上获取客户端的真实IP地址) 然后将请求作为参数传递给它;

  • 问题内容: 我正在尝试通过recvfrom接收数据包的一部分。它实际上是这样的: 数据是这样发送的: 因此,想法是先读取一些元数据,然后再决定是否接收其他内容。问题是如果第二个缓冲区(serialised_buf)开头,我会收到4个’/ 0’字节。这似乎不是序列化的问题,我以前使用过序列化,并且在我一次接收到整个数据包(元和数据)的同时,一切都很酷。关于如何解决的任何想法? PS。我知道我可以跳过

  • 在实验运行在esp32上的UDP服务器时,我发现接收到的数据包的大小限制在1500字节: 20(IP头)8(UDP头)1472(数据),(尽管理论上UDP好像可以支持数据包64K)。这意味着,为了传输更大量的数据,客户端必须将其拆分成若干块并依次发送,而在服务器端,这些数据将需要恢复。我认为这种解决方案的管理费用将相当高。我还知道TOIT提供TCP/IP连接。自然,分组大小在TCP/IP的情况下也

  • 本文向大家介绍PHP获取IP地址所在地信息的实例(使用纯真IP数据库qqwry.dat),包括了PHP获取IP地址所在地信息的实例(使用纯真IP数据库qqwry.dat)的使用技巧和注意事项,需要的朋友参考一下 如下所示: 以上这篇PHP获取IP地址所在地信息的实例(使用纯真IP数据库qqwry.dat)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持呐喊教程。