乐趣区

【Linux系统编程】普通用户绑定(bind)特权端口

有些知识不常使用真的容易忘啊,即使没有忘记,知识提取速度也够下午茶的。
背景
最近在学 Haskell,今天用 Haskell 的 Network.Socket 模块实现了一个简单的基于 TCP 的 daytime 服务程序。程序运行阶段报了以下的错误:
Network.Socket.bind: permission denied (Permission denied)
我的第一反应怀疑是不是本地有服务程序占用端口号 13,然后用命令 netstat -tunl | grep 13 查看,端口号并没有占用,所以第一种可能性不成立。
是不是这个模块有类似的 bug 呢?但并没有查到。不放心,用 C 语言写了同样功能的程序,然后运行也会出错:
bind error: Permission denied
那是不是端口的问题,隐隐约约记得好像是小于 1024 的端口号不是预留给用户的。然后换了一个 >=1024 的端口,果然运行成功了。至此,思路才走上正轨。
实际上小于 1024 的端口是特权端口,普通用户是没有权限绑定的。
那如果我就是要用端口 13 呢,怎么解决呢?
解决方案
1. 使用 root 权限运行最简单的方式就是登录 root 帐号,或者使用 su 切换到 root。如果本机有配置 sudo,普通用户也可使用该命令运行服务程序。
2. 使用 setcap 给服务程序赋予能力上一种方式是使用具有特权的用户,而该种方式是给程序赋予绑定特权端口的能力。操作如下:

使用 setcap ‘CAP_NET_BIND_SERVICE=+ep’ /path/to/program 赋予 (raise) 绑定特权端口的能力
使用 setcap ‘CAP_NET_BIND_SERVICE=-ep’ /path/to/program 清除 (lower) 绑定特权端口的能力
也可使用 setcap -r /path/to/program 清除 (remove) 该程序的所有能力

setcap 简单使用说明

除了 CAP_NET_BIND_SERVICE,还有好多能力,可以参考 capabilities(7)

=、- 是运算符,除此之外还有 +;e 和 p 是标记,除此之外还有 i。可参考 cap_from_text(3) Textual Representation 一节的说明。

setcap 命令对内核有要求,必须 >=2.6.24。

请关注我的公众号哦。

退出移动版