Support SO_PASSCRED

Co-authored-by: Jianfeng Jiang <jiangjianfeng.jjf@antgroup.com>
This commit is contained in:
Ruihan Li 2025-06-25 23:55:40 +08:00 committed by Tate, Hongliang Tian
parent deb60415a6
commit ab897ccd2f
4 changed files with 57 additions and 10 deletions

View File

@ -21,6 +21,7 @@ impl_socket_options!(
pub struct Priority(i32); pub struct Priority(i32);
pub struct Linger(LingerOption); pub struct Linger(LingerOption);
pub struct KeepAlive(bool); pub struct KeepAlive(bool);
pub struct PassCred(bool);
pub struct PeerCred(CUserCred); pub struct PeerCred(CUserCred);
pub struct AcceptConn(bool); pub struct AcceptConn(bool);
pub struct SendBufForce(u32); pub struct SendBufForce(u32);

View File

@ -11,8 +11,8 @@ use crate::{
match_sock_option_mut, match_sock_option_ref, match_sock_option_mut, match_sock_option_ref,
net::socket::{ net::socket::{
options::{ options::{
AcceptConn, KeepAlive, Linger, PeerCred, PeerGroups, Priority, RecvBuf, RecvBufForce, AcceptConn, KeepAlive, Linger, PassCred, PeerCred, PeerGroups, Priority, RecvBuf,
ReuseAddr, ReusePort, SendBuf, SendBufForce, SocketOption, RecvBufForce, ReuseAddr, ReusePort, SendBuf, SendBufForce, SocketOption,
}, },
unix::{CUserCred, UNIX_STREAM_DEFAULT_BUF_SIZE}, unix::{CUserCred, UNIX_STREAM_DEFAULT_BUF_SIZE},
}, },
@ -30,6 +30,7 @@ pub struct SocketOptionSet {
recv_buf: u32, recv_buf: u32,
linger: LingerOption, linger: LingerOption,
keep_alive: bool, keep_alive: bool,
pass_cred: bool,
priority: i32, priority: i32,
} }
@ -42,14 +43,15 @@ impl Default for SocketOptionSet {
recv_buf: MIN_RECVBUF, recv_buf: MIN_RECVBUF,
linger: LingerOption::default(), linger: LingerOption::default(),
keep_alive: false, keep_alive: false,
pass_cred: false,
priority: 0, priority: 0,
} }
} }
} }
impl SocketOptionSet { impl SocketOptionSet {
/// Return the default socket level options for tcp socket. /// Returns the default socket level options for tcp socket.
pub fn new_tcp() -> Self { pub(in crate::net) fn new_tcp() -> Self {
Self { Self {
send_buf: TCP_SEND_BUF_LEN as u32, send_buf: TCP_SEND_BUF_LEN as u32,
recv_buf: TCP_RECV_BUF_LEN as u32, recv_buf: TCP_RECV_BUF_LEN as u32,
@ -57,8 +59,8 @@ impl SocketOptionSet {
} }
} }
/// Return the default socket level options for udp socket. /// Returns the default socket level options for udp socket.
pub fn new_udp() -> Self { pub(in crate::net) fn new_udp() -> Self {
Self { Self {
send_buf: UDP_SEND_PAYLOAD_LEN as u32, send_buf: UDP_SEND_PAYLOAD_LEN as u32,
recv_buf: UDP_RECV_PAYLOAD_LEN as u32, recv_buf: UDP_RECV_PAYLOAD_LEN as u32,
@ -114,6 +116,12 @@ impl SocketOptionSet {
let keep_alive = self.keep_alive(); let keep_alive = self.keep_alive();
socket_keepalive.set(keep_alive); socket_keepalive.set(keep_alive);
}, },
socket_pass_cred: PassCred => {
// This option only affects UNIX sockets. However, it also works well with other
// sockets for setting and getting.
let pass_cred = self.pass_cred();
socket_pass_cred.set(pass_cred);
},
socket_peer_cred: PeerCred => { socket_peer_cred: PeerCred => {
let peer_cred = CUserCred::new_unknown(); let peer_cred = CUserCred::new_unknown();
socket_peer_cred.set(peer_cred); socket_peer_cred.set(peer_cred);
@ -185,6 +193,12 @@ impl SocketOptionSet {
self.set_keep_alive(*keep_alive); self.set_keep_alive(*keep_alive);
return Ok(socket.set_keep_alive(*keep_alive)); return Ok(socket.set_keep_alive(*keep_alive));
}, },
socket_pass_cred: PassCred => {
// This option only affects UNIX sockets. However, it also works well with other
// sockets for setting and getting.
let pass_cred = socket_pass_cred.get().unwrap();
self.set_pass_cred(*pass_cred);
},
socket_sendbuf_force: SendBufForce => { socket_sendbuf_force: SendBufForce => {
check_current_privileged()?; check_current_privileged()?;
let send_buf = socket_sendbuf_force.get().unwrap(); let send_buf = socket_sendbuf_force.get().unwrap();

View File

@ -4,7 +4,7 @@ use super::RawSocketOption;
use crate::{ use crate::{
current_userspace, impl_raw_sock_option_get_only, impl_raw_socket_option, current_userspace, impl_raw_sock_option_get_only, impl_raw_socket_option,
net::socket::options::{ net::socket::options::{
AcceptConn, Error, KeepAlive, Linger, PeerCred, PeerGroups, Priority, RecvBuf, AcceptConn, Error, KeepAlive, Linger, PassCred, PeerCred, PeerGroups, Priority, RecvBuf,
RecvBufForce, ReuseAddr, ReusePort, SendBuf, SendBufForce, SocketOption, RecvBufForce, ReuseAddr, ReusePort, SendBuf, SendBufForce, SocketOption,
}, },
prelude::*, prelude::*,
@ -57,6 +57,7 @@ pub fn new_socket_option(name: i32) -> Result<Box<dyn RawSocketOption>> {
CSocketOptionName::REUSEPORT => Ok(Box::new(ReusePort::new())), CSocketOptionName::REUSEPORT => Ok(Box::new(ReusePort::new())),
CSocketOptionName::PRIORITY => Ok(Box::new(Priority::new())), CSocketOptionName::PRIORITY => Ok(Box::new(Priority::new())),
CSocketOptionName::LINGER => Ok(Box::new(Linger::new())), CSocketOptionName::LINGER => Ok(Box::new(Linger::new())),
CSocketOptionName::PASSCRED => Ok(Box::new(PassCred::new())),
CSocketOptionName::KEEPALIVE => Ok(Box::new(KeepAlive::new())), CSocketOptionName::KEEPALIVE => Ok(Box::new(KeepAlive::new())),
CSocketOptionName::PEERCRED => Ok(Box::new(PeerCred::new())), CSocketOptionName::PEERCRED => Ok(Box::new(PeerCred::new())),
CSocketOptionName::ACCPETCONN => Ok(Box::new(AcceptConn::new())), CSocketOptionName::ACCPETCONN => Ok(Box::new(AcceptConn::new())),
@ -75,6 +76,7 @@ impl_raw_socket_option!(ReusePort);
impl_raw_socket_option!(Priority); impl_raw_socket_option!(Priority);
impl_raw_socket_option!(Linger); impl_raw_socket_option!(Linger);
impl_raw_socket_option!(KeepAlive); impl_raw_socket_option!(KeepAlive);
impl_raw_socket_option!(PassCred);
impl_raw_sock_option_get_only!(PeerCred); impl_raw_sock_option_get_only!(PeerCred);
impl_raw_sock_option_get_only!(AcceptConn); impl_raw_sock_option_get_only!(AcceptConn);
impl_raw_socket_option!(SendBufForce); impl_raw_socket_option!(SendBufForce);

View File

@ -4,7 +4,6 @@
* UNIX stream socket-related socket options. * UNIX stream socket-related socket options.
*/ */
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
@ -83,6 +82,37 @@ FN_TEST(acceptconn)
} }
END_TEST() END_TEST()
FN_TEST(pass_cred)
{
int val = 0;
socklen_t len = sizeof(val);
TEST_RES(getsockopt(sk_tcp, SOL_SOCKET, SO_PASSCRED, &val, &len),
len == 4 && val == 0);
TEST_RES(getsockopt(sk_unbound, SOL_SOCKET, SO_PASSCRED, &val, &len),
len == 4 && val == 0);
TEST_RES(getsockopt(sk_listen, SOL_SOCKET, SO_PASSCRED, &val, &len),
len == 4 && val == 0);
TEST_RES(getsockopt(sk_connected, SOL_SOCKET, SO_PASSCRED, &val, &len),
len == 4 && val == 0);
val = 100;
TEST_SUCC(setsockopt(sk_tcp, SOL_SOCKET, SO_PASSCRED, &val, len));
TEST_SUCC(setsockopt(sk_unbound, SOL_SOCKET, SO_PASSCRED, &val, len));
TEST_SUCC(setsockopt(sk_listen, SOL_SOCKET, SO_PASSCRED, &val, len));
TEST_SUCC(setsockopt(sk_connected, SOL_SOCKET, SO_PASSCRED, &val, len));
TEST_RES(getsockopt(sk_tcp, SOL_SOCKET, SO_PASSCRED, &val, &len),
len == 4 && val == 1);
TEST_RES(getsockopt(sk_unbound, SOL_SOCKET, SO_PASSCRED, &val, &len),
len == 4 && val == 1);
TEST_RES(getsockopt(sk_listen, SOL_SOCKET, SO_PASSCRED, &val, &len),
len == 4 && val == 1);
TEST_RES(getsockopt(sk_connected, SOL_SOCKET, SO_PASSCRED, &val, &len),
len == 4 && val == 1);
}
END_TEST()
FN_TEST(peer_cred) FN_TEST(peer_cred)
{ {
struct cred { struct cred {
@ -94,7 +124,7 @@ FN_TEST(peer_cred)
struct cred ucred = {}; struct cred ucred = {};
socklen_t len = sizeof(ucred); socklen_t len = sizeof(ucred);
TEST_ERRNO(setsockopt(sk_unbound, SOL_SOCKET, SO_PEERCRED, &ucred, len), TEST_ERRNO(setsockopt(sk_tcp, SOL_SOCKET, SO_PEERCRED, &ucred, len),
ENOPROTOOPT); ENOPROTOOPT);
TEST_RES(getsockopt(sk_tcp, SOL_SOCKET, SO_PEERCRED, &ucred, &len), TEST_RES(getsockopt(sk_tcp, SOL_SOCKET, SO_PEERCRED, &ucred, &len),
ucred.pid == 0 && ucred.uid == -1 && ucred.gid == -1); ucred.pid == 0 && ucred.uid == -1 && ucred.gid == -1);
@ -228,4 +258,4 @@ FN_SETUP(cleanup)
CHECK(close(sk_tcp)); CHECK(close(sk_tcp));
CHECK(unlink(addr.sun_path)); CHECK(unlink(addr.sun_path));
} }
END_SETUP() END_SETUP()