我试图通过在Mac上的port forwarding终端上运行一系列命令来在计算机上实现here。我试图通过使用Python中的subprocess
来运行后一个链接中列出的端口映射命令。
我尝试使用subprocess
运行的命令是:
echo "
rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
" | sudo pfctl -ef -
上述命令的我的Python实现:
from subprocess import Popen, PIPE
commands = ['echo', '"rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080"\n', '|', 'sudo', 'pfctl', '-ef', '-']
p = Popen(['sudo', '-S']+commands, stdin=PIPE, stderr=PIPE, universal_newlines=True)
print(p.communicate('root_password\n')[1])#be able to read password for sudo from stdin
但是,此Python脚本不起作用,因为当我运行sudo pfctl -s nat
以在计算机上以预期输出显示所有端口转发规则时
rdr pass inet proto tcp from any to any port = 80 -> 127.0.0.1 port 8080
不显示在外壳上。
但是,运行
echo "
rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
" | sudo pfctl -ef -
确实会产生
rdr pass inet proto tcp from any to any port = 80 -> 127.0.0.1 port 8080
在运行显示命令sudo pfctl -s nat
之后。
如何改进我的subprocess
实现,以便正确输出规则列表?
编辑:奇怪的是,我可以使用sudo pfctl -s nat
subprocess
p = Popen(['sudo', '-S']+'pfctl -s nat'.split(), stdin=PIPE, stderr=PIPE, universal_newlines=True)
print(p.communicate(f'myrootpassword\n')[1]))
在外壳本身中运行时,获得与sudo pfctl -s nat
相同的输出。
我正在macOS Sierra 10.12.5上运行命令和Python尝试。
答案 0 :(得分:2)
您正在尝试使用Popen()
来执行包含多个命令的管道,但这种方式不起作用。这是外壳功能。
我相信您需要多次调用Popen()
,每个命令一次,并将它们的stdin / stdout明确挂钩。
答案 1 :(得分:1)
subprocess.Popen
显式转义外壳元字符(包括|
)。例如:
>>> p = Popen(['echo', 'abcdefg', '|', 'wc'], stdout=PIPE, universal_newlines=True)
>>> p.communicate()
('abcdefg | wc\n', None)
请注意,abcdefg
没有通过管道传递到wc
,因为管道字符被转义并解释为字符而不是过程管道。因此,您的命令不会通过管道传递到sudo中,因为管道字符已转义。您可以使用Popen
(将字符串作为命令,而不是列表)来强制 shell=True
解释shell元字符:
>>> p = Popen(" ".join(['echo', 'abcdefg', '|', 'wc']), stdout=PIPE, universal_newlines=True, shell=True)
>>> p.communicate()
(' 1 1 8\n', None)
如果您不信任您的输入,Shell元字符将被转义,这是有充分的理由的(以防止注入攻击)。如果您这样做了,我认为您是这样做的,因为您要传入根pw,则只需使用shell=True
。
HTH。