Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
R
re6stnet
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
2
Issues
2
List
Boards
Labels
Milestones
Merge Requests
4
Merge Requests
4
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
re6stnet
Commits
308eaa7f
Commit
308eaa7f
authored
Mar 23, 2022
by
Léo-Paul Géneau
👾
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add multicast routing
See merge request
!37
parent
badb9a77
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
159 additions
and
0 deletions
+159
-0
README.rst
README.rst
+3
-0
re6st/cli/node.py
re6st/cli/node.py
+8
-0
re6st/multicast.py
re6st/multicast.py
+147
-0
setup.py
setup.py
+1
-0
No files found.
README.rst
View file @
308eaa7f
...
...
@@ -59,6 +59,7 @@ Requirements
- geoip2: `python library`_ and `country lite database`_ (optional)
- python-miniupnpc for UPnP support (optional)
- for the demo: miniupnpd_, Graphviz, Screen_, Nemu_, MultiPing_, psutil_
- for multicast: pim-dm_ and PyYAML_
See also `setup.py` for Python dependencies.
...
...
@@ -70,6 +71,8 @@ See also `setup.py` for Python dependencies.
.. _Screen: http://savannah.gnu.org/projects/screen
.. _python library: https://pypi.org/project/geoip2/
.. _country lite database: https://dev.maxmind.com/geoip/geoip2/geolite2/
.. _pim-dm: https://pypi.org/project/pim-dm/
.. _PyYAML: https://pypi.org/project/PyYAML/
Installation
============
...
...
re6st/cli/node.py
View file @
308eaa7f
...
...
@@ -50,6 +50,8 @@ def getConfig():
_
(
'-I'
,
'--main-interface'
,
metavar
=
'IFACE'
,
default
=
'lo'
,
help
=
"Set re6stnet IP on given interface. Any interface not used for"
" tunnelling can be chosen."
)
_
(
'-m'
,
'--multicast'
,
action
=
'store_true'
,
help
=
"Enable multicast routing."
)
_
(
'--up'
,
metavar
=
'CMD'
,
help
=
"Shell command to run after successful initialization."
)
_
(
'--daemon'
,
action
=
'append'
,
metavar
=
'CMD'
,
...
...
@@ -364,6 +366,12 @@ def main():
R
[
r
]
=
partial
(
tunnel_manager
.
handleServerEvent
,
r
)
x
.
close
()
if
config
.
multicast
:
from
re6st.multicast
import
PimDm
pimdm
=
PimDm
()
cleanup
.
append
(
pimdm
.
run
(
config
.
iface_list
,
config
.
run
).
stop
)
R
[
pimdm
.
s_netlink
]
=
pimdm
.
addInterfaceWhenReady
ip
(
'addr'
,
my_ip
+
'/%s'
%
len
(
subnet
),
'dev'
,
config
.
main_interface
)
if_rt
=
[
'ip'
,
'-6'
,
'route'
,
'del'
,
...
...
re6st/multicast.py
0 → 100644
View file @
308eaa7f
import
os
,
struct
,
subprocess
,
time
,
yaml
from
ctypes
import
(
Structure
,
Union
,
POINTER
,
pointer
,
c_ushort
,
c_byte
,
c_void_p
,
c_char_p
,
c_uint
,
c_int
,
CDLL
,
util
as
ctypes_util
,
)
from
socket
import
socket
,
AF_INET6
,
AF_NETLINK
,
NETLINK_ROUTE
,
SOCK_RAW
from
.
import
utils
RTMGRP_IPV6_IFINFO
=
0x800
RTM_NEWLINK
=
16
IFLA_IFNAME
=
3
class
struct_sockaddr
(
Structure
):
_fields_
=
[
(
'sa_family'
,
c_ushort
),
(
'sa_data'
,
c_byte
*
14
),
]
class
union_ifa_ifu
(
Union
):
_fields_
=
[
(
'ifu_broadaddr'
,
POINTER
(
struct_sockaddr
)),
(
'ifu_dstaddr'
,
POINTER
(
struct_sockaddr
)),
]
class
struct_ifaddrs
(
Structure
):
pass
struct_ifaddrs
.
_fields_
=
[
(
'ifa_next'
,
POINTER
(
struct_ifaddrs
)),
(
'ifa_name'
,
c_char_p
),
(
'ifa_flags'
,
c_uint
),
(
'ifa_addr'
,
POINTER
(
struct_sockaddr
)),
(
'ifa_netmask'
,
POINTER
(
struct_sockaddr
)),
(
'ifa_ifu'
,
union_ifa_ifu
),
(
'ifa_data'
,
c_void_p
),
]
libc
=
CDLL
(
ctypes_util
.
find_library
(
'c'
),
use_errno
=
True
)
getifaddrs
=
libc
.
getifaddrs
getifaddrs
.
restype
=
c_int
getifaddrs
.
argtypes
=
[
POINTER
(
POINTER
(
struct_ifaddrs
))]
freeifaddrs
=
libc
.
freeifaddrs
freeifaddrs
.
restype
=
None
freeifaddrs
.
argtypes
=
[
POINTER
(
struct_ifaddrs
)]
class
unpacker
(
object
):
def
__init__
(
self
,
buf
):
self
.
_buf
=
buf
self
.
_offset
=
0
def
__call__
(
self
,
fmt
):
s
=
struct
.
Struct
(
fmt
)
result
=
s
.
unpack_from
(
self
.
_buf
,
self
.
_offset
)
self
.
_offset
+=
s
.
size
return
result
class
PimDm
(
object
):
def
__init__
(
self
):
s_netlink
=
socket
(
AF_NETLINK
,
SOCK_RAW
,
NETLINK_ROUTE
)
s_netlink
.
setblocking
(
False
)
s_netlink
.
bind
((
os
.
getpid
(),
RTMGRP_IPV6_IFINFO
))
self
.
s_netlink
=
s_netlink
self
.
started
=
False
def
addInterface
(
self
,
ifname
):
while
not
self
.
isStarted
():
time
.
sleep
(
0.5
)
subprocess
.
call
([
'pim-dm'
,
'-6'
,
'-aisr'
,
ifname
])
subprocess
.
call
([
'pim-dm'
,
'-aimld'
,
ifname
])
def
addInterfaceWhenReady
(
self
):
if
not
self
.
not_ready_iface_set
:
return
data
=
self
.
s_netlink
.
recv
(
65535
)
unpack
=
unpacker
(
data
)
msg_len
,
msg_type
,
flags
,
seq
,
pid
=
unpack
(
"=LHHLL"
)
if
msg_type
!=
RTM_NEWLINK
:
return
family
,
_
,
if_type
,
index
,
flags
,
change
=
unpack
(
"=BBHiII"
)
while
msg_len
-
unpack
.
_offset
:
rta_len
,
rta_type
=
unpack
(
"=HH"
)
if
rta_len
<
4
:
break
rta_data
=
unpack
(
"%ds"
%
rta_len
)[
0
].
rstrip
(
'
\
0
\
n
\
1
'
)
if
rta_type
==
IFLA_IFNAME
:
if
rta_data
in
self
.
not_ready_iface_set
\
and
rta_data
in
interfaceUpSet
():
self
.
addInterface
(
rta_data
)
self
.
not_ready_iface_set
.
remove
(
rta_data
)
break
unpack
.
_offset
+=
(
rta_len
-
1
)
&
~
(
4
-
1
)
def
isStarted
(
self
):
if
not
self
.
started
:
self
.
started
=
os
.
path
.
exists
(
'/run/pim-dm/0'
)
return
self
.
started
def
run
(
self
,
iface_list
,
run_path
):
# pim-dm requires interface to be up at startup,
# but can handle interfaces going down then up again
iface_set
=
set
(
iface_list
)
up_set
=
interfaceUpSet
()
self
.
not_ready_iface_set
=
iface_set
-
up_set
iface_set
&=
up_set
enabled
=
((
'enabled'
,
True
),
(
'state_refresh'
,
True
))
conf
=
{
'PIM-DM'
:
{
'Interfaces'
:
dict
.
fromkeys
(
iface_set
,
{
'ipv6'
:
dict
(
enabled
)}),
},
'MLD'
:
{
'Interfaces'
:
dict
.
fromkeys
(
iface_set
,
dict
(
enabled
[:
1
])),
},
}
conf_file_path
=
os
.
path
.
join
(
run_path
,
'pim-dm.conf'
)
with
open
(
conf_file_path
,
'w'
)
as
conf_file
:
yaml
.
dump
(
conf
,
conf_file
)
return
utils
.
Popen
([
'pim-dm'
,
'-config'
,
conf_file_path
])
def
ifap_iter
(
ifa
):
'''Iterate over linked list of ifaddrs'''
while
ifa
:
ifa
=
ifa
.
contents
yield
ifa
ifa
=
ifa
.
ifa_next
def
interfaceUpSet
():
ifap
=
POINTER
(
struct_ifaddrs
)()
getifaddrs
(
pointer
(
ifap
))
try
:
return
{
ifa
.
ifa_name
for
ifa
in
ifap_iter
(
ifap
)
if
ifa
.
ifa_addr
and
ifa
.
ifa_addr
.
contents
.
sa_family
==
AF_INET6
}
finally
:
freeifaddrs
(
ifap
)
setup.py
View file @
308eaa7f
...
...
@@ -94,6 +94,7 @@ setup(
install_requires
=
[
'pyOpenSSL >= 0.13'
,
'miniupnpc'
],
extras_require
=
{
'geoip'
:
[
'geoip2'
],
'multicast'
:
[
'PyYAML'
],
},
#dependency_links = [
# "http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.7.20120714.tar.gz#egg=miniupnpc-1.7",
...
...
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