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 Linger(LingerOption);
pub struct KeepAlive(bool);
pub struct PassCred(bool);
pub struct PeerCred(CUserCred);
pub struct AcceptConn(bool);
pub struct SendBufForce(u32);

View File

@ -11,8 +11,8 @@ use crate::{
match_sock_option_mut, match_sock_option_ref,
net::socket::{
options::{
AcceptConn, KeepAlive, Linger, PeerCred, PeerGroups, Priority, RecvBuf, RecvBufForce,
ReuseAddr, ReusePort, SendBuf, SendBufForce, SocketOption,
AcceptConn, KeepAlive, Linger, PassCred, PeerCred, PeerGroups, Priority, RecvBuf,
RecvBufForce, ReuseAddr, ReusePort, SendBuf, SendBufForce, SocketOption,
},
unix::{CUserCred, UNIX_STREAM_DEFAULT_BUF_SIZE},
},
@ -30,6 +30,7 @@ pub struct SocketOptionSet {
recv_buf: u32,
linger: LingerOption,
keep_alive: bool,
pass_cred: bool,
priority: i32,
}
@ -42,14 +43,15 @@ impl Default for SocketOptionSet {
recv_buf: MIN_RECVBUF,
linger: LingerOption::default(),
keep_alive: false,
pass_cred: false,
priority: 0,
}
}
}
impl SocketOptionSet {
/// Return the default socket level options for tcp socket.
pub fn new_tcp() -> Self {
/// Returns the default socket level options for tcp socket.
pub(in crate::net) fn new_tcp() -> Self {
Self {
send_buf: TCP_SEND_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.
pub fn new_udp() -> Self {
/// Returns the default socket level options for udp socket.
pub(in crate::net) fn new_udp() -> Self {
Self {
send_buf: UDP_SEND_PAYLOAD_LEN as u32,
recv_buf: UDP_RECV_PAYLOAD_LEN as u32,
@ -114,6 +116,12 @@ impl SocketOptionSet {
let keep_alive = self.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 => {
let peer_cred = CUserCred::new_unknown();
socket_peer_cred.set(peer_cred);
@ -185,6 +193,12 @@ impl SocketOptionSet {
self.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 => {
check_current_privileged()?;
let send_buf = socket_sendbuf_force.get().unwrap();

View File

@ -4,7 +4,7 @@ use super::RawSocketOption;
use crate::{
current_userspace, impl_raw_sock_option_get_only, impl_raw_socket_option,
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,
},
prelude::*,
@ -57,6 +57,7 @@ pub fn new_socket_option(name: i32) -> Result<Box<dyn RawSocketOption>> {
CSocketOptionName::REUSEPORT => Ok(Box::new(ReusePort::new())),
CSocketOptionName::PRIORITY => Ok(Box::new(Priority::new())),
CSocketOptionName::LINGER => Ok(Box::new(Linger::new())),
CSocketOptionName::PASSCRED => Ok(Box::new(PassCred::new())),
CSocketOptionName::KEEPALIVE => Ok(Box::new(KeepAlive::new())),
CSocketOptionName::PEERCRED => Ok(Box::new(PeerCred::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!(Linger);
impl_raw_socket_option!(KeepAlive);
impl_raw_socket_option!(PassCred);
impl_raw_sock_option_get_only!(PeerCred);
impl_raw_sock_option_get_only!(AcceptConn);
impl_raw_socket_option!(SendBufForce);

View File

@ -4,7 +4,6 @@
* UNIX stream socket-related socket options.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
@ -83,6 +82,37 @@ FN_TEST(acceptconn)
}
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)
{
struct cred {
@ -94,7 +124,7 @@ FN_TEST(peer_cred)
struct cred 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);
TEST_RES(getsockopt(sk_tcp, SOL_SOCKET, SO_PEERCRED, &ucred, &len),
ucred.pid == 0 && ucred.uid == -1 && ucred.gid == -1);
@ -228,4 +258,4 @@ FN_SETUP(cleanup)
CHECK(close(sk_tcp));
CHECK(unlink(addr.sun_path));
}
END_SETUP()
END_SETUP()