nginxrustunix-socket

why does nginx say "91: Protocol wrong type for socket" when it tries to connect to my rust-based unix socket server?


i'm writing a sort of tool to analyse traffic that goes to nginx on my server by logging them into a database, then perform certain actions on them. i've decided the best way to do this would be to analyse the access_log, because i'll be able to see all the requests in there. rather than continuously reading the log file, which i'd have to parse, i thought i'd use nginx's syslog feature. i wrote this line in my nginx.conf:

access_log syslog:server=unix:/run/user/1000/logtool.sock,severity=info combined;

and ran my rust program. i saw no connections in my rust program, so checked the nginx.log, and saw this:

2025/05/10 13:00:03 [alert] 40303#40303: connect() failed (91: Protocol wrong type for socket) while logging to syslog, server: unix:/run/user/1000/logtool.sock

why is that? am i opening the socket wrong? this is the code i used:

use std::io::prelude::*;
use std::os::unix::net::{UnixListener, UnixStream};

fn handle_client(mut socket: UnixStream) -> std::io::Result<()> {
    let addr = socket.peer_addr();
    println!("a client ({addr:?}) connected");
    loop {
        let mut buf = Vec::new();
        let amt = socket.read_to_end(&mut buf)?;
        if amt == 0 {
            println!("the client {addr:?} disconnected");
            break;
        }
        dbg!(buf);
   }
   Ok(())
}

fn main() -> std::io::Result<()> {
    let socket_path = format!(
        "{}/logtool.sock",
        std::env::var("XDG_RUNTIME_DIR").unwrap_or("/tmp".to_string())
    );
    let _ = std::fs::remove_file(&socket_path);
    let listener = UnixListener::bind(socket_path)?;

    loop {
        for stream in listener.incoming() {
            match stream {
                Ok(socket) => handle_client(socket)?,
                Err(err) => eprintln!("cannot accept connection: {err:?}"),
            }
        }
    }
}

i have also used the .accept() method of doing it instead of .incoming(), but the same thing happens. how do i fix this problem?


Solution

  • nginx expects a datagram socket, not a stream socket. you can create a datagram socket like this:

    use std::os::unix::net::UnixDatagram;
    
    fn main() -> std::io::Result<()> {
        let socket_path = format!(
            "{}/logtool.sock",
            std::env::var("XDG_RUNTIME_DIR").unwrap_or("/tmp".to_string())
        );
        let _ = std::fs::remove_file(&socket_path);
        let listener = UnixDatagram::bind(socket_path)?;
    
        loop {
            let mut buf = vec![0; 1_024];
            let read = listener.recv(&mut buf)?;
            let buf = &buf[..read];
            dbg!(buf);
        }
    }