Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SocketAddr from UnixDatagram recv_from missing the last character #2230

Closed
zonyitoo opened this issue Feb 9, 2020 · 7 comments
Closed

SocketAddr from UnixDatagram recv_from missing the last character #2230

zonyitoo opened this issue Feb 9, 2020 · 7 comments
Labels
A-tokio Area: The main tokio crate C-bug Category: This is a bug. M-net Module: tokio/net

Comments

@zonyitoo
Copy link
Contributor

zonyitoo commented Feb 9, 2020

Version

0.2.11

Platform

Darwin 19.3.0 Darwin Kernel Version 19.3.0: Thu Jan  9 20:58:23 PST 2020; root:xnu-6153.81.5~1/RELEASE_X86_64 x86_64

Subcrates

net

Description

Server:

let mut socket = UnixDatagram::bind("/tmp/shadowsocks-manager.sock")?;

let mut buf = [0u8; 1024];
loop {
    let (recv_len, src_addr) = socket.recv_from(&mut buf).await?;
    println!("{:?}", src_addr);
}

Client (in Python):

import socket

cli = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
cli.bind('/tmp/shadowsocks-manager-c.sock')  # NOTE: this is the name of client's socket
cli.connect('/tmp/shadowsocks-manager.sock')

cli.send(b'ping')
print(cli.recv(1506))

Server receives 4 bytes sent from client, and print:

"/tmp/shadowsocks-manager-c.soc" (pathname)

Where is that missing k?

@zonyitoo
Copy link
Contributor Author

zonyitoo commented Feb 9, 2020

I think the problem is the len - 1 in: https://github.com/tokio-rs/mio/blob/master/src/sys/unix/uds/socketaddr.rs#L43

@kleimkuhler
Copy link
Contributor

@zonyitoo I have not reproduced this using a Python client, but I don't think the issue here is in the linked code.

Tokio 0.2.11 still uses Mio 0.6.21 which in turn uses mio-uds. The code linked above is in a Mio 0.7 alpha.

To address that first, the path shortening is similar to std where OS path lengths are expected to be null-terminated. The path length subtraction is then needed to drop the null-terminator.

What may be happening here is that the Python client is not doing what std expects as linked above? If a socket's path length is not null-terminated, then the server's println! dispatches to this Debug impl where it then drops the last byte.

Maybe try making sure the client's bound path is null-terminated. Does that answer your question? I know there are a few links provided in this, but let me know if anything is not clear.

@zonyitoo
Copy link
Contributor Author

More test with libstd's UnixDatagram:

use std::os::unix::net::UnixDatagram;

fn main() {
    let socket = UnixDatagram::bind("/tmp/shadowsocks-manager.sock").unwrap();

    let mut buf = [0u8; 65536];
    loop {
        let (n, src_addr) = socket.recv_from(&mut buf).unwrap();
        println!("size={} src={:?}", n, src_addr);
    }
}

Client is the same python script. And I got this result:

size=4 src="/tmp/shadowsocks-manager-c.soc" (pathname)

@kleimkuhler Could you try it on OS X?

@zonyitoo
Copy link
Contributor Author

zonyitoo commented Feb 11, 2020

Maybe try making sure the client's bound path is null-terminated.

I think the problem is OS X's bound path is not null-terminated. I am doing test with C.

@zonyitoo
Copy link
Contributor Author

zonyitoo commented Feb 11, 2020

Test program in C

#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
    int ret = 0;

    int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (fd < 0) {
        perror("socket");
        return EXIT_FAILURE;
    }

    struct sockaddr_un baddr;
    memset(&baddr, 0, sizeof(baddr));

    const char* BIND_PATH = "/tmp/shadowsocks-manager.sock";
    baddr.sun_family = AF_UNIX;
    strcpy(baddr.sun_path, BIND_PATH);

    unlink(BIND_PATH);

    if ((ret = bind(fd, (struct sockaddr*)&baddr, sizeof(baddr))) < 0) {
        perror("bind");
        close(fd);
        return EXIT_FAILURE;
    }

    char buf[65536];

    for (;;) {
        struct sockaddr_un caddr;
        memset(&caddr, 0, sizeof(caddr));
        socklen_t caddr_len = sizeof(caddr);

        ssize_t rcount = 0;
        if ((rcount = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr*)&caddr, &caddr_len)) < 0) {
            perror("recvfrom");
            close(fd);
            return EXIT_FAILURE;
        }

        printf("recvfrom ret=%zd caddr_len=%u sun_len=%u sun_family=%d path=%s\n",
               rcount,
               caddr_len,
               caddr.sun_len,
               caddr.sun_family,
               caddr.sun_path);
    }

    return 0;
}

And test with the same Python client:

recvfrom ret=4 caddr_len=33 sun_len=33 sun_family=1 path=/tmp/shadowsocks-manager-c.sock

NOTE: the length of /tmp/shadowsocks-manager-c.sock is 31.

@zonyitoo
Copy link
Contributor Author

Ok, I found the problem.

In OS X, sockaddr_un is defined as

/*
 * [XSI] Definitions for UNIX IPC domain.
 */
struct  sockaddr_un {
	unsigned char   sun_len;        /* sockaddr len including null */
	sa_family_t     sun_family;     /* [XSI] AF_UNIX */
	char            sun_path[104];  /* [XSI] path name (gag) */
};

but Linux defines sockaddr_un as

/* Structure describing the address of an AF_LOCAL (aka AF_UNIX) socket.  */
struct sockaddr_un
  {
    __SOCKADDR_COMMON (sun_);
    char sun_path[108];		/* Path name.  */
  };

and __SOCKADDR_COMMON is defined as

#define	__SOCKADDR_COMMON(sa_prefix) \
  sa_family_t sa_prefix##family

So OS X has one more byte (sun_len) before sun_path! That's why!

@Darksonn Darksonn added A-tokio Area: The main tokio crate C-bug Category: This is a bug. M-net Module: tokio/net labels Jul 25, 2020
@baum
Copy link

baum commented Mar 29, 2023

Should be closed this one 🖖

@Darksonn Darksonn closed this as not planned Won't fix, can't repro, duplicate, stale Mar 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio Area: The main tokio crate C-bug Category: This is a bug. M-net Module: tokio/net
Projects
None yet
Development

No branches or pull requests

4 participants