#upnp #open-ports #port #csv #daemon #file #opening

app upnp-daemon

通过UPnP持续打开端口的守护进程

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

Download history 41/week @ 2024-04-13 3/week @ 2024-06-29 16/week @ 2024-07-06 37/week @ 2024-07-27

每月下载量 53

WTFPL 许可证

54KB
388

UPnP守护进程

badge github badge crates.io badge license

通过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数组,并且包含所有必需的字段即可。

由于第二个条目中的addressnull,如果愿意,也可以完全省略。另外,任何没有在下面记录的键都将被守护进程静默忽略,因此您可以使用它们作为自己的内部注释。因此,配置也可能看起来像

[
  {
    "rationale": "This port is needed for an awesome application!",
    "may-be-deleted": false,
    "port": 12347,
    "protocol": "TCP",
    "duration": 60,
    "comment": "Test 3"
  }
]

守护进程将忽略键rationalemay-be-deleted

另外,请注意,即使您只想添加一个端口映射,您也需要指定一个JSON数组。

字段

  • address

    为端口映射应添加的IP地址。该字段可以是空的,在这种情况下,将尝试所有已连接的接口,直到一个网关报告成功。如果IP地址是动态的并且不一致,这很有用。

    如果您想为外部设备添加端口映射,或者知道您的机器的地址并想稍微加快处理速度,请填写IP地址。

    您也可以使用CIDR表示法输入IP地址。在这种情况下,IP范围将与所有已连接的接口进行核对,并且只有匹配的接口才会被考虑。如果您不知道当前的IP地址(或者它可能不时更改),但知道路由器的DHCP配置,这很有用。

    这样的IP地址可能是192.168.0.10192.168.0.0/24甚至192.168.0

    更多示例可以在责任库的文档中找到:https://docs.rs/cidr-utils/0.5.10/cidr_utils/index.html

  • 端口号

    为给定IP地址打开的端口号。请注意,upnp-daemon目前很贪婪,如果已经存在端口号映射,它将被删除并重新添加为给定的IP地址。这可能在未来的版本中可配置。

  • 协议

    为打开给定端口的协议。可能的值是 UDPTCP

  • 持续时间

    端口号映射的租期(以秒为单位)。请注意,一些支持UPnP的路由器可能会忽略此值,因此不要仅依赖于此。

  • 注释

    关于端口号映射原因的注释。将存储在路由器中与映射一起。

依赖项

~11–22MB
~340K SLoC