9个版本 (5个重大更新)
0.6.0 | 2024年4月7日 |
---|---|
0.5.2 | 2023年11月1日 |
0.5.1 | 2023年8月5日 |
0.4.1 | 2023年6月11日 |
0.1.0 | 2020年8月8日 |
#1 in #upnp
每月下载量 53
54KB
388 行
UPnP守护进程
通过UPnP持续打开端口的守护进程。
动机
有许多程序需要某些网络端口打开才能正常工作,但并不提供通过UPnP自动打开端口的选项。当然,人们可能会争论UPnP带来的安全影响,但如果你愿意承担风险,那么例如你的Web服务器无法从互联网访问,因为你忘记打开端口80,或者你的路由器重新启动并清除了打开端口表,或者你的机器由于某种原因没有静态IP地址,因此无法添加一致的端口映射,这只会让人感到烦恼。
正因为这种挫败感,我创建了upnp-daemon
,这是一个用Rust编写的轻量级服务,它会定期检查包含你定义的端口映射的文件,并将它们发送到你的路由器。主要用途是您只需启动一次,并将其作为后台服务永久运行。每次迭代都会重新读取包含端口映射的文件,因此您可以在运行时添加新的映射。
安装
upnp-daemon可以通过Cargo通过crates.io
轻松安装
cargo install --locked upnp-daemon
请注意,这里需要使用--locked
标志以确保具有与应用程序标记和测试时相同的精确依赖项。如果没有它,您可能会得到依赖项的最新版本,但如果依赖项更改了某些功能,则可能会出现未定义和意外的行为。如果依赖项的公共API更改太多,应用程序甚至可能无法构建。
另外,可以从GitHub发布页面下载预构建的二进制文件。
使用
Usage: upnp-daemon [OPTIONS] --file <FILE>
Options:
-f, --file <FILE> The file (or "-" for stdin) with the port descriptions
--format <FORMAT> The format of the configuration file [default: csv] [possible values: csv, json]
-d, --csv-delimiter <CSV_DELIMITER> Field delimiter when using CSV files [default: ;]
-F, --foreground Run in foreground instead of forking to background
-1, --oneshot Run just one time instead of continuously
-n, --interval <INTERVAL> Specify update interval in seconds [default: 60]
--close-ports-on-exit Close specified ports on program exit
--only-close-ports Only close specified ports and exit
--pid-file <PID_FILE> Absolute path to PID file for daemon mode [default: /tmp/upnp-daemon.pid]
-h, --help Print help
-V, --version Print version
在最基本的情况下,调用可能如下所示
upnp-daemon --file ports.csv
这将启动一个后台进程(守护进程),每分钟从CSV文件(见配置文件格式)中读取端口映射,并要求适当的路由器打开这些端口。
进程的PID默认将写入/tmp/upnp-daemon.pid
,并独占锁定,确保同一时间只有一个实例运行。要退出,请杀死该文件中写入的PID。
Bash可以这样操作
kill $(</tmp/upnp-daemon.pid)
如果您希望PID写入另一个文件,可能是因为您故意想要运行多个实例,或者因为您的守护进程监视器期望文件在另一个位置,您可以使用--pid-file
选项来选择自己的文件路径。由于技术原因,此PID文件必须始终以绝对路径给出。请注意,此应用程序不会创建文件夹,因此PID文件的父文件夹需要事先存在。当然,运行应用程序的用户需要对该文件夹具有写入权限。
给Windows用户的注意事项:用于将此程序发送到后台的daemonize
库仅在类Unix系统上工作。您仍然可以在Windows上安装并使用此程序,但它将像使用--foreground
选项启动一样运行(参见下面)。因此,您在Windows上也不会看到--pid-file
选项,因为在Windows上它没有用途。
从标准输入读取
根据实际情况,可能需要从stdin读取端口配置。在这种情况下,您可以给出伪文件名"-",如下所示
generate-configuration | upnp-daemon --file -
由假想的generate-configuration
生成的配置需要与第config文件格式中描述的格式相同。
注意:如果您实际上想要读取名为-
的文件,请给出绝对或相对文件路径,如下所示
upnp-daemon --file ./-
前台操作
某些服务监视器期望服务在前台启动,以便它们可以使用自己的自定义函数处理它们。对于这种情况,您可以使用foreground
标志,如下所示
upnp-daemon --foreground --file ports.csv
这将使程序在前台运行。您可以通过发出SIGINT
(Ctrl-C)等命令来终止它。
给Windows用户的注意事项:此程序版本的Windows中不存在此选项标志。相反,前台操作是默认操作模式,因为由于技术限制,它不能在那里发送到后台。
一次性模式
如果您只想测试配置,而不让守护进程无限期运行,您可以使用oneshot
标志,如下所示
upnp-daemon --foreground --oneshot --file ports.csv
当然,您可以省略foreground
标志,但这样您将不知道进程何时完成,这可能需要一些时间,具体取决于映射文件的大小。
关闭端口
如果您想在程序退出时关闭打开的端口,您可以使用close-ports-on-exit
标志,如下所示
upnp-daemon --close-ports-on-exit --file ports.csv
如果程序后来通过使用kill
命令或通过在前台模式下发送SIGINT
来终止,配置文件中当前定义的端口将被关闭。错误将被记录,但不是致命的,因此它们不会导致程序恐慌。这些错误可能发生在,例如,端口最初没有打开的情况下。
如果您只想关闭所有定义的端口,甚至不运行主程序,您可以使用--only-close-ports
标志,如下所示
upnp-daemon --foreground --only-close-ports --file ports.csv
这里的foreground
标志是可选的,但如果需要知道所有端口都已关闭,它是有用的,因为程序仅在那时终止。
日志记录
如果您想激活日志记录以更好地了解程序在底层做了什么,您需要设置环境变量RUST_LOG
,如下所示
RUST_LOG=info upnp-daemon --foreground --file ports.csv
要使日志记录更加详细,请尝试将日志级别设置为debug
RUST_LOG=debug upnp-daemon --foreground --file ports.csv
请注意,如果没有使用foreground
激活日志记录,是没有意义的,因为在守护进程模式下输出(包括stdout和stderr)将不会被保存。这可能在未来的版本中改变。
配置文件格式
配置文件可以是CSV(目前默认)或JSON(使用--format json
)。字段的名字和内容始终相同。
CSV
端口映射文件的格式是一个简单的CSV文件,如下面的示例所示
address;port;protocol;duration;comment
192.168.0.10;12345;UDP;60;Test 1
;12346;TCP;60;Test 2
请注意,目前第一行是必需的,它需要将字段精确地映射到内部选项。
使用--csv-delimiter
选项,您可以选择任意字符作为CSV文件中的字段分隔符。默认情况下,我们使用分号,但如果您更愿意使用常规逗号,只需这样说明--csv-delimiter ','
。
请注意,您的shell可能会解释分隔符(例如,分号在bash中用于分隔两个命令),因此请确保正确地转义它。
JSON
具有上述内容的JSON格式配置文件可能如下所示
[
{
"address": "192.168.0.10",
"port": 12345,
"protocol": "UDP",
"duration": 60,
"comment": "Test 1"
},
{
"address": null,
"port": 12346,
"protocol": "TCP",
"duration": 60,
"comment": "Test 2"
}
]
换行符和缩进只是为了可读性,您可以按任何方式格式化它。您甚至可以输入一行,只要它是一个有效的JSON数组,并且包含所有必需的字段即可。
由于第二个条目中的address
是null
,如果愿意,也可以完全省略。另外,任何没有在下面记录的键都将被守护进程静默忽略,因此您可以使用它们作为自己的内部注释。因此,配置也可能看起来像
[
{
"rationale": "This port is needed for an awesome application!",
"may-be-deleted": false,
"port": 12347,
"protocol": "TCP",
"duration": 60,
"comment": "Test 3"
}
]
守护进程将忽略键rationale
和may-be-deleted
。
另外,请注意,即使您只想添加一个端口映射,您也需要指定一个JSON数组。
字段
-
address
为端口映射应添加的IP地址。该字段可以是空的,在这种情况下,将尝试所有已连接的接口,直到一个网关报告成功。如果IP地址是动态的并且不一致,这很有用。
如果您想为外部设备添加端口映射,或者知道您的机器的地址并想稍微加快处理速度,请填写IP地址。
您也可以使用CIDR表示法输入IP地址。在这种情况下,IP范围将与所有已连接的接口进行核对,并且只有匹配的接口才会被考虑。如果您不知道当前的IP地址(或者它可能不时更改),但知道路由器的DHCP配置,这很有用。
这样的IP地址可能是
192.168.0.10
或192.168.0.0/24
甚至192.168.0
。更多示例可以在责任库的文档中找到:https://docs.rs/cidr-utils/0.5.10/cidr_utils/index.html
-
端口号
为给定IP地址打开的端口号。请注意,upnp-daemon目前很贪婪,如果已经存在端口号映射,它将被删除并重新添加为给定的IP地址。这可能在未来的版本中可配置。
-
协议
为打开给定端口的协议。可能的值是
UDP
和TCP
。 -
持续时间
端口号映射的租期(以秒为单位)。请注意,一些支持UPnP的路由器可能会忽略此值,因此不要仅依赖于此。
-
注释
关于端口号映射原因的注释。将存储在路由器中与映射一起。
依赖项
~11–22MB
~340K SLoC