Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
sshuttle
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
pub
sshuttle
Commits
5e904913
Commit
5e904913
authored
Jan 18, 2017
by
Ermal Luci
Committed by
Brian May
Jan 28, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Re-introduce ipfw support for sshuttle on FreeBSD with support for --DNS option as well
Sponsored-by: rsync.net
parent
e8ceccc3
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
271 additions
and
1 deletion
+271
-1
__init__.py
sshuttle/methods/__init__.py
+2
-0
ipfw.py
sshuttle/methods/ipfw.py
+268
-0
options.py
sshuttle/options.py
+1
-1
No files found.
sshuttle/methods/__init__.py
View file @
5e904913
...
...
@@ -98,6 +98,8 @@ def get_auto_method():
method_name
=
"nat"
elif
_program_exists
(
'pfctl'
):
method_name
=
"pf"
elif
_program_exists
(
'ipfw'
):
method_name
=
"ipfw"
else
:
raise
Fatal
(
"can't find either iptables or pfctl; check your PATH"
)
...
...
sshuttle/methods/ipfw.py
0 → 100644
View file @
5e904913
import
os
import
sys
import
struct
import
subprocess
as
ssubprocess
from
sshuttle.methods
import
BaseMethod
from
sshuttle.helpers
import
log
,
debug1
,
debug3
,
\
Fatal
,
family_to_string
recvmsg
=
None
try
:
# try getting recvmsg from python
import
socket
as
pythonsocket
getattr
(
pythonsocket
.
socket
,
"recvmsg"
)
socket
=
pythonsocket
recvmsg
=
"python"
except
AttributeError
:
# try getting recvmsg from socket_ext library
try
:
import
socket_ext
getattr
(
socket_ext
.
socket
,
"recvmsg"
)
socket
=
socket_ext
recvmsg
=
"socket_ext"
except
ImportError
:
import
socket
IP_BINDANY
=
24
IP_RECVDSTADDR
=
7
SOL_IPV6
=
41
IPV6_RECVDSTADDR
=
74
if
recvmsg
==
"python"
:
def
recv_udp
(
listener
,
bufsize
):
debug3
(
'Accept UDP python using recvmsg.
\n
'
)
data
,
ancdata
,
msg_flags
,
srcip
=
listener
.
recvmsg
(
4096
,
socket
.
CMSG_SPACE
(
4
))
dstip
=
None
family
=
None
for
cmsg_level
,
cmsg_type
,
cmsg_data
in
ancdata
:
if
cmsg_level
==
socket
.
SOL_IP
and
cmsg_type
==
IP_RECVDSTADDR
:
port
=
53
ip
=
socket
.
inet_ntop
(
socket
.
AF_INET
,
cmsg_data
[
0
:
4
])
dstip
=
(
ip
,
port
)
break
return
(
srcip
,
dstip
,
data
)
elif
recvmsg
==
"socket_ext"
:
def
recv_udp
(
listener
,
bufsize
):
debug3
(
'Accept UDP using socket_ext recvmsg.
\n
'
)
srcip
,
data
,
adata
,
flags
=
listener
.
recvmsg
((
bufsize
,),
socket
.
CMSG_SPACE
(
4
))
dstip
=
None
family
=
None
for
a
in
adata
:
if
a
.
cmsg_level
==
socket
.
SOL_IP
and
a
.
cmsg_type
==
IP_RECVDSTADDR
:
port
=
53
ip
=
socket
.
inet_ntop
(
socket
.
AF_INET
,
cmsg_data
[
0
:
4
])
dstip
=
(
ip
,
port
)
break
return
(
srcip
,
dstip
,
data
[
0
])
else
:
def
recv_udp
(
listener
,
bufsize
):
debug3
(
'Accept UDP using recvfrom.
\n
'
)
data
,
srcip
=
listener
.
recvfrom
(
bufsize
)
return
(
srcip
,
None
,
data
)
def
ipfw_rule_exists
(
n
):
argv
=
[
'ipfw'
,
'list'
]
env
=
{
'PATH'
:
os
.
environ
[
'PATH'
],
'LC_ALL'
:
"C"
,
}
p
=
ssubprocess
.
Popen
(
argv
,
stdout
=
ssubprocess
.
PIPE
,
env
=
env
)
found
=
False
for
line
in
p
.
stdout
:
if
line
.
startswith
(
b
'
%05
d '
%
n
):
if
not
(
'ipttl 42'
in
line
or
'check-state'
in
line
):
log
(
'non-sshuttle ipfw rule:
%
r
\n
'
%
line
.
strip
())
raise
Fatal
(
'non-sshuttle ipfw rule #
%
d already exists!'
%
n
)
found
=
True
rv
=
p
.
wait
()
if
rv
:
raise
Fatal
(
'
%
r returned
%
d'
%
(
argv
,
rv
))
return
found
_oldctls
=
{}
def
_fill_oldctls
(
prefix
):
argv
=
[
'sysctl'
,
prefix
]
env
=
{
'PATH'
:
os
.
environ
[
'PATH'
],
'LC_ALL'
:
"C"
,
}
p
=
ssubprocess
.
Popen
(
argv
,
stdout
=
ssubprocess
.
PIPE
,
env
=
env
)
for
line
in
p
.
stdout
:
line
=
line
.
decode
()
assert
(
line
[
-
1
]
==
'
\n
'
)
(
k
,
v
)
=
line
[:
-
1
]
.
split
(
': '
,
1
)
_oldctls
[
k
]
=
v
.
strip
()
rv
=
p
.
wait
()
if
rv
:
raise
Fatal
(
'
%
r returned
%
d'
%
(
argv
,
rv
))
if
not
line
:
raise
Fatal
(
'
%
r returned no data'
%
(
argv
,))
def
_sysctl_set
(
name
,
val
):
argv
=
[
'sysctl'
,
'-w'
,
'
%
s=
%
s'
%
(
name
,
val
)]
debug1
(
'>>
%
s
\n
'
%
' '
.
join
(
argv
))
return
ssubprocess
.
call
(
argv
,
stdout
=
open
(
'/dev/null'
,
'w'
))
_changedctls
=
[]
def
sysctl_set
(
name
,
val
,
permanent
=
False
):
PREFIX
=
'net.inet.ip'
assert
(
name
.
startswith
(
PREFIX
+
'.'
))
val
=
str
(
val
)
if
not
_oldctls
:
_fill_oldctls
(
PREFIX
)
if
not
(
name
in
_oldctls
):
debug1
(
'>> No such sysctl:
%
r
\n
'
%
name
)
return
False
oldval
=
_oldctls
[
name
]
if
val
!=
oldval
:
rv
=
_sysctl_set
(
name
,
val
)
if
rv
==
0
and
permanent
:
debug1
(
'>> ...saving permanently in /etc/sysctl.conf
\n
'
)
f
=
open
(
'/etc/sysctl.conf'
,
'a'
)
f
.
write
(
'
\n
'
'# Added by sshuttle
\n
'
'
%
s=
%
s
\n
'
%
(
name
,
val
))
f
.
close
()
else
:
_changedctls
.
append
(
name
)
return
True
def
ipfw
(
*
args
):
argv
=
[
'ipfw'
,
'-q'
]
+
list
(
args
)
debug1
(
'>>
%
s
\n
'
%
' '
.
join
(
argv
))
rv
=
ssubprocess
.
call
(
argv
)
if
rv
:
raise
Fatal
(
'
%
r returned
%
d'
%
(
argv
,
rv
))
def
ipfw_noexit
(
*
args
):
argv
=
[
'ipfw'
,
'-q'
]
+
list
(
args
)
debug1
(
'>>
%
s
\n
'
%
' '
.
join
(
argv
))
ssubprocess
.
call
(
argv
)
class
Method
(
BaseMethod
):
def
get_supported_features
(
self
):
result
=
super
(
Method
,
self
)
.
get_supported_features
()
result
.
ipv6
=
False
result
.
udp
=
False
#NOTE: Almost there, kernel patch needed
result
.
dns
=
True
return
result
def
get_tcp_dstip
(
self
,
sock
):
return
sock
.
getsockname
()
def
recv_udp
(
self
,
udp_listener
,
bufsize
):
srcip
,
dstip
,
data
=
recv_udp
(
udp_listener
,
bufsize
)
if
not
dstip
:
debug1
(
"-- ignored UDP from
%
r: "
"couldn't determine destination IP address
\n
"
%
(
srcip
,))
return
None
return
srcip
,
dstip
,
data
def
send_udp
(
self
,
sock
,
srcip
,
dstip
,
data
):
if
not
srcip
:
debug1
(
"-- ignored UDP to
%
r: "
"couldn't determine source IP address
\n
"
%
(
dstip
,))
return
#debug3('Sending SRC: %r DST: %r\n' % (srcip, dstip))
sender
=
socket
.
socket
(
sock
.
family
,
socket
.
SOCK_DGRAM
)
sender
.
setsockopt
(
socket
.
SOL_IP
,
IP_BINDANY
,
1
)
sender
.
setsockopt
(
socket
.
SOL_SOCKET
,
socket
.
SO_REUSEADDR
,
1
)
sender
.
setsockopt
(
socket
.
SOL_SOCKET
,
socket
.
SO_REUSEPORT
,
1
)
sender
.
setsockopt
(
socket
.
SOL_IP
,
socket
.
IP_TTL
,
42
)
sender
.
bind
(
srcip
)
sender
.
sendto
(
data
,
dstip
)
sender
.
close
()
def
setup_udp_listener
(
self
,
udp_listener
):
if
udp_listener
.
v4
is
not
None
:
udp_listener
.
v4
.
setsockopt
(
socket
.
SOL_IP
,
IP_RECVDSTADDR
,
1
)
#if udp_listener.v6 is not None:
# udp_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVDSTADDR, 1)
def
setup_firewall
(
self
,
port
,
dnsport
,
nslist
,
family
,
subnets
,
udp
):
# IPv6 not supported
if
family
not
in
[
socket
.
AF_INET
]:
raise
Exception
(
'Address family "
%
s" unsupported by ipfw method_name'
%
family_to_string
(
family
))
#XXX: Any risk from this?
ipfw_noexit
(
'delete'
,
'1'
)
while
_changedctls
:
name
=
_changedctls
.
pop
()
oldval
=
_oldctls
[
name
]
_sysctl_set
(
name
,
oldval
)
if
subnets
or
dnsport
:
sysctl_set
(
'net.inet.ip.fw.enable'
,
1
)
ipfw
(
'add'
,
'1'
,
'check-state'
,
'ip'
,
'from'
,
'any'
,
'to'
,
'any'
)
ipfw
(
'add'
,
'1'
,
'skipto'
,
'2'
,
'tcp'
,
'from'
,
'any'
,
'to'
,
'table(125)'
)
ipfw
(
'add'
,
'1'
,
'fwd'
,
'127.0.0.1,
%
d'
%
port
,
'tcp'
,
'from'
,
'any'
,
'to'
,
'table(126)'
,
'not'
,
'ipttl'
,
'42'
,
'keep-state'
,
'setup'
)
ipfw_noexit
(
'table'
,
'124'
,
'flush'
)
dnscount
=
0
for
f
,
ip
in
[
i
for
i
in
nslist
if
i
[
0
]
==
family
]:
ipfw
(
'table'
,
'124'
,
'add'
,
'
%
s'
%
(
ip
))
dnscount
+=
1
if
dnscount
>
0
:
ipfw
(
'add'
,
'1'
,
'fwd'
,
'127.0.0.1,
%
d'
%
dnsport
,
'udp'
,
'from'
,
'any'
,
'to'
,
'table(124)'
,
'not'
,
'ipttl'
,
'42'
)
"""if udp:
ipfw('add', '1', 'skipto', '2',
'udp',
'from', 'any', 'to', 'table(125)')
ipfw('add', '1', 'fwd', '127.0.0.1,
%
d'
%
port,
'udp',
'from', 'any', 'to', 'table(126)',
'not', 'ipttl', '42')
"""
ipfw
(
'add'
,
'1'
,
'allow'
,
'udp'
,
'from'
,
'any'
,
'to'
,
'any'
,
'ipttl'
,
'42'
)
if
subnets
:
# create new subnet entries
for
f
,
swidth
,
sexclude
,
snet
\
in
sorted
(
subnets
,
key
=
lambda
s
:
s
[
1
],
reverse
=
True
):
if
sexclude
:
ipfw
(
'table'
,
'125'
,
'add'
,
'
%
s/
%
s'
%
(
snet
,
swidth
))
else
:
ipfw
(
'table'
,
'126'
,
'add'
,
'
%
s/
%
s'
%
(
snet
,
swidth
))
def
restore_firewall
(
self
,
port
,
family
,
udp
):
if
family
not
in
[
socket
.
AF_INET
]:
raise
Exception
(
'Address family "
%
s" unsupported by tproxy method'
%
family_to_string
(
family
))
ipfw_noexit
(
'delete'
,
'1'
)
ipfw_noexit
(
'table'
,
'124'
,
'flush'
)
ipfw_noexit
(
'table'
,
'125'
,
'flush'
)
ipfw_noexit
(
'table'
,
'126'
,
'flush'
)
sshuttle/options.py
View file @
5e904913
...
...
@@ -162,7 +162,7 @@ parser.add_argument(
)
parser
.
add_argument
(
"--method"
,
choices
=
[
"auto"
,
"nat"
,
"tproxy"
,
"pf"
],
choices
=
[
"auto"
,
"nat"
,
"tproxy"
,
"pf"
,
"ipfw"
],
metavar
=
"TYPE"
,
default
=
"auto"
,
help
=
"""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment