• Linux 网络选项 setsockopt 设置


    Linux 网络选项 setsockopt 设置

    函数原型

    #include
    /**
     * @brief 设置与某个套接字关联的选项
     * 
     * @param fd 套接字
     * @param level:选项所在的协议层,支持SOLSOCKET、IPPROTOTCP、IPPROTOIP和IPPROTOIPV6
     * 		一般选择SOLSOCKET
     * @param optname:需设置的选项,而有部分选项需在listen/connect调用前设置才有效
     * @param optval:指针,指向存放选项值的缓冲区
     * @param optlen:长度
     * @return int: 0 返回设置成功,-1 设置失败,errno 出错原因
     */
    extern int setsockopt (int fd, int level, int optname,
    		       const void *optval, socklen_t optlen);
    		       
    extern int getsockopt (int fd, int level, int optname,
    		       void *restrict optval,
    		       socklen_t *restrict optlen);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    linux 5.10 内核系统调用声明

    // net/socket.c
    SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
    		char __user *, optval, int, optlen)
    {
    	return __sys_setsockopt(fd, level, optname, optval, optlen);
    }
    // net/socket.c line:2096
    int __sys_setsockopt(int fd, int level, int optname, char __user *user_optval,
    		int optlen)
    {
    	...
    	if (level == SOL_SOCKET && !sock_use_custom_sol_socket(sock))
    		err = sock_setsockopt(sock, level, optname, optval, optlen);
    	else if (unlikely(!sock->ops->setsockopt))
    		err = -EOPNOTSUPP;
    	else
    		err = sock->ops->setsockopt(sock, level, optname, optval,
    					    optlen);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    optname选项设置, 可以参考 man 7 socket

    // net/core/sock.c line:823
    int sock_setsockopt(struct socket *sock, int level, int optname,
    		    sockptr_t optval, unsigned int optlen)
    {
    	...
    	if (optname == SO_BINDTODEVICE)
    		return sock_setbindtodevice(sk, optval, optlen);
    	...
    	switch (optname) {
    	case SO_DEBUG:
    		if (val && !capable(CAP_NET_ADMIN))
    			ret = -EACCES;
    		else
    			sock_valbool_flag(sk, SOCK_DBG, valbool);
    		break;
    	case SO_REUSEADDR: // 允许重用本地地址
    		sk->sk_reuse = (valbool ? SK_CAN_REUSE : SK_NO_REUSE);
    		break;
    	case SO_REUSEPORT:  // 允许重用本地端口
    		sk->sk_reuseport = valbool;
    		break;
    	case SO_TYPE:
    	case SO_PROTOCOL:
    	case SO_DOMAIN:
    	case SO_ERROR:
    		ret = -ENOPROTOOPT;
    		break;
    	case SO_DONTROUTE: // 不查找路由 
    		sock_valbool_flag(sk, SOCK_LOCALROUTE, valbool);
    		sk_dst_reset(sk);
    		break;
    	case SO_BROADCAST: // 允许发送广播数据
    		sock_valbool_flag(sk, SOCK_BROADCAST, valbool);
    		break;
    	...
    	case SO_KEEPALIVE: // 保持连接
    		if (sk->sk_prot->keepalive)
    			sk->sk_prot->keepalive(sk, valbool);
    		sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool);
    		break;
    
    	case SO_OOBINLINE: // 带外数据放入正常数据流
    		sock_valbool_flag(sk, SOCK_URGINLINE, valbool);
    		break;
    
    	case SO_NO_CHECK:
    		sk->sk_no_check_tx = valbool;
    		break;
    
    	case SO_PRIORITY:
    		if ((val >= 0 && val <= 6) ||
    		    ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
    			sk->sk_priority = val;
    		else
    			ret = -EPERM;
    		break;
    	....
    	case SO_RCVTIMEO_OLD:
    	case SO_RCVTIMEO_NEW:
    		ret = sock_set_timeout(&sk->sk_rcvtimeo, optval,
    				       optlen, optname == SO_RCVTIMEO_OLD);
    		break;
    
    	case SO_SNDTIMEO_OLD:
    	case SO_SNDTIMEO_NEW:
    		ret = sock_set_timeout(&sk->sk_sndtimeo, optval,
    				       optlen, optname == SO_SNDTIMEO_OLD);
    		break;
    
    	case SO_ATTACH_FILTER: {
    		struct sock_fprog fprog;
    
    		ret = copy_bpf_fprog_from_user(&fprog, optval, optlen);
    		if (!ret)
    			ret = sk_attach_filter(&fprog, sk);
    		break;
    	}
    	...
    	case SO_INCOMING_CPU:
    		WRITE_ONCE(sk->sk_incoming_cpu, val);
    		break;
    
    	case SO_CNX_ADVICE:
    		if (val == 1)
    			dst_negative_advice(sk);
    		break;
    
    	case SO_ZEROCOPY:
    		...
    		break;
    	...
    
    	default:
    		ret = -ENOPROTOOPT;
    		break;
    	}
    	release_sock(sk);
    	return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99

    绑定指定网卡

    参考setsockopt 的 SO_BINDTODEVICE 套接口选项

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct ifreq interface;
    // 网卡名称
    strncpy(interface.ifr_name, "wlp3s0", IFNAMSIZ);
    if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&interface, sizeof(interface)) < 0) {
        perror("wlp3s0-client:SO_BINDTODEVICE failed");
        return -1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    01_Elasticsearch入门介绍
    前端面试基础题——12
    【Linux】翻山越岭——进程地址空间
    cloudstack中ConsoleProxyManagerImpl
    Gitlab使用
    spark SQLQueryTestSuite sql 自动化测试用例
    有钱还系统源码 人人还众筹还钱模式还贷系统源码
    〖Python 数据库开发实战 - MySQL篇㉓〗- 单行子查询与多行子查询语法规则
    数据结构 【树状数组】【线段树】【珂朵莉树】
    统计数字会撒谎
  • 原文地址:https://blog.csdn.net/qq_41146650/article/details/126698227