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
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
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
Yohann D'Anello
re6stnet
Commits
d7a4d73f
Commit
d7a4d73f
authored
Jul 01, 2018
by
Julien Muchembled
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New option to prevent tunnelling accross borders of listed countries
parent
6b45d7ea
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
147 additions
and
27 deletions
+147
-27
debian/control
debian/control
+1
-1
debian/init.d
debian/init.d
+3
-0
debian/rules
debian/rules
+1
-1
re6st/cache.py
re6st/cache.py
+41
-12
re6st/cli/registry.py
re6st/cli/registry.py
+3
-1
re6st/registry.py
re6st/registry.py
+6
-4
re6st/tunnel.py
re6st/tunnel.py
+88
-7
re6st/version.py
re6st/version.py
+1
-1
setup.py
setup.py
+3
-0
No files found.
debian/control
View file @
d7a4d73f
...
@@ -10,7 +10,7 @@ Package: re6stnet
...
@@ -10,7 +10,7 @@ Package: re6stnet
Architecture: all
Architecture: all
Depends: ${misc:Depends}, ${python:Depends}, python-pkg-resources, python-openssl (>= 0.13), openvpn (>= 2.3), babeld (= 1.6.2-nxd1), iproute2 | iproute, openssl
Depends: ${misc:Depends}, ${python:Depends}, python-pkg-resources, python-openssl (>= 0.13), openvpn (>= 2.3), babeld (= 1.6.2-nxd1), iproute2 | iproute, openssl
Recommends: ${python:Recommends}, logrotate
Recommends: ${python:Recommends}, logrotate
Suggests: ndisc6
Suggests:
${python:Suggests},
ndisc6
Conflicts: re6st-node
Conflicts: re6st-node
Replaces: re6st-node
Replaces: re6st-node
Description: resilient, scalable, IPv6 network application
Description: resilient, scalable, IPv6 network application
debian/init.d
View file @
d7a4d73f
...
@@ -31,6 +31,9 @@ SCRIPTNAME=/etc/init.d/$NAME
...
@@ -31,6 +31,9 @@ SCRIPTNAME=/etc/init.d/$NAME
#
#
do_start
()
do_start
()
{
{
if
[
-
r
$
CONFDIR
/
GeoLite2
-
Country
.
mmdb
]
then
export
GEOIP2_MMDB
=$
CONFDIR
/
GeoLite2
-
Country
.
mmdb
fi
#
Return
#
Return
#
0
if
daemon
has
been
started
#
0
if
daemon
has
been
started
#
1
if
daemon
was
already
running
#
1
if
daemon
was
already
running
...
...
debian/rules
View file @
d7a4d73f
...
@@ -15,7 +15,7 @@ include debian/common.mk
...
@@ -15,7 +15,7 @@ include debian/common.mk
override_dh_python2
:
override_dh_python2
:
sed
-i
/^miniupnpc
$$
/d
`
find
$(TMP)
/usr
-name
requires.txt
`
sed
-i
/^miniupnpc
$$
/d
`
find
$(TMP)
/usr
-name
requires.txt
`
dh_python2
--recommends
=
miniupnpc
dh_python2
--recommends
=
miniupnpc
--suggests
=
geoip2
override_dh_auto_clean
:
override_dh_auto_clean
:
make clean
make clean
...
...
re6st/cache.py
View file @
d7a4d73f
import
json
,
logging
,
os
,
sqlite3
,
socket
,
subprocess
,
sys
,
time
,
zlib
import
json
,
logging
,
os
,
sqlite3
,
socket
,
subprocess
,
sys
,
time
,
zlib
from
itertools
import
chain
from
.registry
import
RegistryClient
from
.registry
import
RegistryClient
from
.
import
utils
,
version
,
x509
from
.
import
utils
,
version
,
x509
class
Cache
(
object
):
class
Cache
(
object
):
crl
=
()
def
__init__
(
self
,
db_path
,
registry
,
cert
,
db_size
=
200
):
def
__init__
(
self
,
db_path
,
registry
,
cert
,
db_size
=
200
):
self
.
_prefix
=
cert
.
prefix
self
.
_prefix
=
cert
.
prefix
self
.
_db_size
=
db_size
self
.
_db_size
=
db_size
...
@@ -25,7 +24,8 @@ class Cache(object):
...
@@ -25,7 +24,8 @@ class Cache(object):
peer TEXT PRIMARY KEY NOT NULL,
peer TEXT PRIMARY KEY NOT NULL,
try INTEGER NOT NULL DEFAULT 0)"""
)
try INTEGER NOT NULL DEFAULT 0)"""
)
q
(
"CREATE INDEX volatile.stat_try ON stat(try)"
)
q
(
"CREATE INDEX volatile.stat_try ON stat(try)"
)
q
(
"INSERT INTO volatile.stat (peer) SELECT prefix FROM peer"
)
q
(
"INSERT INTO volatile.stat (peer)"
" SELECT prefix FROM peer WHERE prefix"
)
self
.
_db
.
commit
()
self
.
_db
.
commit
()
self
.
_loadConfig
(
self
.
_selectConfig
(
q
))
self
.
_loadConfig
(
self
.
_selectConfig
(
q
))
try
:
try
:
...
@@ -71,10 +71,16 @@ class Cache(object):
...
@@ -71,10 +71,16 @@ class Cache(object):
def
_loadConfig
(
self
,
config
):
def
_loadConfig
(
self
,
config
):
cls
=
self
.
__class__
cls
=
self
.
__class__
logging
.
debug
(
"Loading network parameters:"
)
logging
.
debug
(
"Loading network parameters:"
)
self
.
crl
=
self
.
same_country
=
()
for
k
,
v
in
config
:
for
k
,
v
in
config
:
if
k
==
'crl'
:
# BBB
k
=
'crl:json'
if
k
.
endswith
(
':json'
):
k
=
k
[:
-
5
]
v
=
json
.
loads
(
v
)
if
k
==
'crl'
:
if
k
==
'crl'
:
v
=
set
(
json
.
loads
(
v
)
)
v
=
set
(
v
)
el
if
hasattr
(
cls
,
k
):
if
hasattr
(
cls
,
k
):
continue
continue
setattr
(
self
,
k
,
v
)
setattr
(
self
,
k
,
v
)
logging
.
debug
(
"- %s: %r"
,
k
,
v
)
logging
.
debug
(
"- %s: %r"
,
k
,
v
)
...
@@ -83,13 +89,20 @@ class Cache(object):
...
@@ -83,13 +89,20 @@ class Cache(object):
logging
.
info
(
"Getting new network parameters from registry..."
)
logging
.
info
(
"Getting new network parameters from registry..."
)
try
:
try
:
# TODO: When possible, the registry should be queried via the re6st.
# TODO: When possible, the registry should be queried via the re6st.
config
=
json
.
loads
(
zlib
.
decompress
(
x
=
json
.
loads
(
zlib
.
decompress
(
self
.
_registry
.
getNetworkConfig
(
self
.
_prefix
)))
self
.
_registry
.
getNetworkConfig
(
self
.
_prefix
)))
base64
=
config
.
pop
(
''
,
())
base64
=
x
.
pop
(
''
,
())
config
=
dict
((
str
(
k
),
v
.
decode
(
'base64'
)
if
k
in
base64
else
config
=
{}
str
(
v
)
if
type
(
v
)
is
unicode
else
v
)
for
k
,
v
in
x
.
iteritems
():
for
k
,
v
in
config
.
iteritems
())
k
=
str
(
k
)
config
[
'crl'
]
=
json
.
dumps
(
config
[
'crl'
])
if
k
in
base64
:
v
=
v
.
decode
(
'base64'
)
elif
type
(
v
)
is
unicode
:
v
=
str
(
v
)
elif
isinstance
(
v
,
(
list
,
dict
)):
k
+=
':json'
v
=
json
.
dumps
(
v
)
config
[
k
]
=
v
except
socket
.
error
,
e
:
except
socket
.
error
,
e
:
logging
.
warning
(
e
)
logging
.
warning
(
e
)
return
return
...
@@ -186,6 +199,22 @@ class Cache(object):
...
@@ -186,6 +199,22 @@ class Cache(object):
(
prefix
,)).
fetchone
()
(
prefix
,)).
fetchone
()
return
r
and
r
[
0
]
return
r
and
r
[
0
]
@
property
def
my_address
(
self
):
for
x
,
in
self
.
_db
.
execute
(
"SELECT address FROM peer WHERE NOT prefix"
):
return
x
return
''
@
my_address
.
setter
def
my_address
(
self
,
*
args
):
with
self
.
_db
as
db
:
db
.
execute
(
"INSERT OR REPLACE INTO peer VALUES ('', ?)"
,
args
)
@
my_address
.
deleter
def
my_address
(
self
):
with
self
.
_db
as
db
:
db
.
execute
(
"DELETE FROM peer WHERE NOT prefix"
)
# Exclude our own address from results in case it is there, which may
# Exclude our own address from results in case it is there, which may
# happen if a node change its certificate without clearing the cache.
# happen if a node change its certificate without clearing the cache.
# IOW, one should probably always put our own address there.
# IOW, one should probably always put our own address there.
...
...
re6st/cli/registry.py
View file @
d7a4d73f
...
@@ -5,7 +5,7 @@ from SocketServer import ThreadingTCPServer
...
@@ -5,7 +5,7 @@ from SocketServer import ThreadingTCPServer
from
urlparse
import
parse_qsl
from
urlparse
import
parse_qsl
if
're6st'
not
in
sys
.
modules
:
if
're6st'
not
in
sys
.
modules
:
sys
.
path
[
0
]
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
sys
.
path
[
0
]))
sys
.
path
[
0
]
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
sys
.
path
[
0
]))
from
re6st
import
ctl
,
registry
,
utils
,
version
from
re6st
import
registry
,
utils
,
version
# To generate server ca and key with serial for 2001:db8:42::/48
# To generate server ca and key with serial for 2001:db8:42::/48
# openssl req -nodes -new -x509 -key ca.key -set_serial 0x120010db80042 -days 3650 -out ca.crt
# openssl req -nodes -new -x509 -key ca.key -set_serial 0x120010db80042 -days 3650 -out ca.crt
...
@@ -132,6 +132,8 @@ def main():
...
@@ -132,6 +132,8 @@ def main():
help
=
"Interval in seconds between two tunnel refresh: the worst"
help
=
"Interval in seconds between two tunnel refresh: the worst"
" tunnel is closed if the number of client tunnels has reached"
" tunnel is closed if the number of client tunnels has reached"
" its maximum number (client-count)."
)
" its maximum number (client-count)."
)
_
(
'--same-country'
,
action
=
'append'
,
metavar
=
"CODE"
,
help
=
"prevent tunnelling accross borders of listed countries"
)
config
=
parser
.
parse_args
()
config
=
parser
.
parse_args
()
...
...
re6st/registry.py
View file @
d7a4d73f
...
@@ -76,11 +76,11 @@ class RegistryServer(object):
...
@@ -76,11 +76,11 @@ class RegistryServer(object):
"email TEXT NOT NULL"
,
"email TEXT NOT NULL"
,
"prefix_len INTEGER NOT NULL"
,
"prefix_len INTEGER NOT NULL"
,
"date INTEGER NOT NULL"
)
"date INTEGER NOT NULL"
)
if
utils
.
sqliteCreateTable
(
self
.
db
,
"cert"
,
utils
.
sqliteCreateTable
(
self
.
db
,
"cert"
,
"prefix TEXT PRIMARY KEY NOT NULL"
,
"prefix TEXT PRIMARY KEY NOT NULL"
,
"email TEXT"
,
"email TEXT"
,
"cert TEXT"
)
:
"cert TEXT"
)
self
.
db
.
execute
(
"INSERT
INTO cert VALUES ('',null,null)"
)
self
.
db
.
execute
(
"INSERT OR IGNORE
INTO cert VALUES ('',null,null)"
)
utils
.
sqliteCreateTable
(
self
.
db
,
"crl"
,
utils
.
sqliteCreateTable
(
self
.
db
,
"crl"
,
"serial INTEGER PRIMARY KEY NOT NULL"
,
"serial INTEGER PRIMARY KEY NOT NULL"
,
# Expiration date of revoked certificate.
# Expiration date of revoked certificate.
...
@@ -122,6 +122,8 @@ class RegistryServer(object):
...
@@ -122,6 +122,8 @@ class RegistryServer(object):
}
}
if
self
.
config
.
ipv4
:
if
self
.
config
.
ipv4
:
kw
[
'ipv4'
],
kw
[
'ipv4_sublen'
]
=
self
.
config
.
ipv4
kw
[
'ipv4'
],
kw
[
'ipv4_sublen'
]
=
self
.
config
.
ipv4
if
self
.
config
.
same_country
:
kw
[
'same_country'
]
=
self
.
config
.
same_country
for
x
in
(
'client_count'
,
'encrypt'
,
'hello'
,
for
x
in
(
'client_count'
,
'encrypt'
,
'hello'
,
'max_clients'
,
'min_protocol'
,
'tunnel_refresh'
):
'max_clients'
,
'min_protocol'
,
'tunnel_refresh'
):
kw
[
x
]
=
getattr
(
self
.
config
,
x
)
kw
[
x
]
=
getattr
(
self
.
config
,
x
)
...
@@ -138,7 +140,7 @@ class RegistryServer(object):
...
@@ -138,7 +140,7 @@ class RegistryServer(object):
# Example to avoid all nodes to restart at the same time:
# Example to avoid all nodes to restart at the same time:
# kw['delay_restart'] = 600 * random.random()
# kw['delay_restart'] = 600 * random.random()
kw
[
'version'
]
=
self
.
version
.
encode
(
'base64'
)
kw
[
'version'
]
=
self
.
version
.
encode
(
'base64'
)
self
.
network_config
=
zlib
.
compress
(
json
.
dumps
(
kw
))
self
.
network_config
=
zlib
.
compress
(
json
.
dumps
(
kw
)
,
9
)
# The 3 first bits code the number of bytes.
# The 3 first bits code the number of bytes.
def
encodeVersion
(
self
,
version
):
def
encodeVersion
(
self
,
version
):
...
...
re6st/tunnel.py
View file @
d7a4d73f
import
errno
,
json
,
logging
,
os
,
random
import
errno
,
json
,
logging
,
os
,
random
,
socket
import
s
ocket
,
subprocess
,
struct
,
time
,
weakref
import
s
ubprocess
,
struct
,
sys
,
time
,
weakref
from
collections
import
defaultdict
,
deque
from
collections
import
defaultdict
,
deque
from
bisect
import
bisect
,
insort
from
bisect
import
bisect
,
insort
from
OpenSSL
import
crypto
from
OpenSSL
import
crypto
...
@@ -7,6 +7,27 @@ from . import ctl, plib, rina, utils, version, x509
...
@@ -7,6 +7,27 @@ from . import ctl, plib, rina, utils, version, x509
PORT
=
326
PORT
=
326
family_dict
=
{
socket
.
AF_INET
:
'IPv4'
,
socket
.
AF_INET6
:
'IPv6'
,
}
proto_dict
=
{
'tcp4'
:
(
socket
.
AF_INET
,
socket
.
SOL_TCP
),
'udp4'
:
(
socket
.
AF_INET
,
socket
.
SOL_UDP
),
'tcp6'
:
(
socket
.
AF_INET6
,
socket
.
SOL_TCP
),
'udp6'
:
(
socket
.
AF_INET6
,
socket
.
SOL_UDP
),
}
proto_dict
[
'tcp'
]
=
proto_dict
[
'tcp4'
]
proto_dict
[
'udp'
]
=
proto_dict
[
'udp4'
]
def
resolve
(
ip
,
port
,
proto
):
try
:
family
,
proto
=
proto_dict
[
proto
]
except
KeyError
:
return
None
,
()
return
family
,
(
x
[
-
1
][
0
]
for
x
in
socket
.
getaddrinfo
(
ip
,
port
,
family
,
0
,
proto
))
class
MultiGatewayManager
(
dict
):
class
MultiGatewayManager
(
dict
):
...
@@ -172,6 +193,7 @@ class BaseTunnelManager(object):
...
@@ -172,6 +193,7 @@ class BaseTunnelManager(object):
NEED_RESTART
=
frozenset
((
'babel_default'
,
'encrypt'
,
'hello'
,
NEED_RESTART
=
frozenset
((
'babel_default'
,
'encrypt'
,
'hello'
,
'ipv4'
,
'ipv4_sublen'
))
'ipv4'
,
'ipv4_sublen'
))
_geoiplookup
=
None
_forward
=
None
_forward
=
None
_next_rina
=
True
_next_rina
=
True
...
@@ -188,6 +210,31 @@ class BaseTunnelManager(object):
...
@@ -188,6 +210,31 @@ class BaseTunnelManager(object):
address_dict
=
defaultdict
(
list
)
address_dict
=
defaultdict
(
list
)
for
family
,
address
in
address
:
for
family
,
address
in
address
:
address_dict
[
family
]
+=
address
address_dict
[
family
]
+=
address
if
any
(
address_dict
.
itervalues
()):
del
cache
.
my_address
else
:
for
address
in
utils
.
parse_address
(
cache
.
my_address
):
try
:
proto
=
proto_dict
[
address
[
2
]]
except
KeyError
:
continue
address_dict
[
proto
[
0
]].
append
(
address
)
db
=
os
.
getenv
(
'GEOIP2_MMDB'
)
if
db
:
from
geoip2
import
database
,
errors
country
=
database
.
Reader
(
db
).
country
def
geoiplookup
(
ip
):
try
:
return
country
(
ip
).
country
.
iso_code
except
errors
.
AddressNotFoundError
:
return
self
.
_geoiplookup
=
geoiplookup
self
.
_country
=
{}
for
address
in
address_dict
.
itervalues
():
self
.
_updateCountry
(
address
)
elif
cache
.
same_country
:
sys
.
exit
(
"Can not respect 'same_country' network configuration"
" (GEOIP2_MMDB not set)"
)
self
.
_address
=
dict
((
family
,
utils
.
dump_address
(
address
))
self
.
_address
=
dict
((
family
,
utils
.
dump_address
(
address
))
for
family
,
address
in
address_dict
.
iteritems
()
for
family
,
address
in
address_dict
.
iteritems
()
if
address
)
if
address
)
...
@@ -589,11 +636,23 @@ class BaseTunnelManager(object):
...
@@ -589,11 +636,23 @@ class BaseTunnelManager(object):
'
\
7
%s (%s)'
%
(
msg
,
os
.
uname
()[
2
]))
'
\
7
%s (%s)'
%
(
msg
,
os
.
uname
()[
2
]))
break
break
def
_updateCountry
(
self
,
address
):
for
address
in
address
:
family
,
ip
=
resolve
(
*
address
)
for
ip
in
ip
:
country
=
self
.
_geoiplookup
(
ip
)
if
country
:
if
self
.
_country
.
get
(
family
)
!=
country
:
self
.
_country
[
family
]
=
country
logging
.
info
(
'%s country: %s'
,
family_dict
[
family
],
country
)
return
class
TunnelManager
(
BaseTunnelManager
):
class
TunnelManager
(
BaseTunnelManager
):
NEED_RESTART
=
BaseTunnelManager
.
NEED_RESTART
.
union
((
NEED_RESTART
=
BaseTunnelManager
.
NEED_RESTART
.
union
((
'client_count'
,
'max_clients'
,
'tunnel_refresh'
))
'client_count'
,
'max_clients'
,
'
same_country'
,
'
tunnel_refresh'
))
def
__init__
(
self
,
control_socket
,
cache
,
cert
,
openvpn_args
,
def
__init__
(
self
,
control_socket
,
cache
,
cert
,
openvpn_args
,
timeout
,
client_count
,
iface_list
,
address
,
ip_changed
,
timeout
,
client_count
,
iface_list
,
address
,
ip_changed
,
...
@@ -780,16 +839,35 @@ class TunnelManager(BaseTunnelManager):
...
@@ -780,16 +839,35 @@ class TunnelManager(BaseTunnelManager):
if
prefix
in
self
.
_served
or
prefix
in
self
.
_connection_dict
:
if
prefix
in
self
.
_served
or
prefix
in
self
.
_connection_dict
:
return
False
return
False
assert
prefix
!=
self
.
_prefix
,
self
.
__dict__
assert
prefix
!=
self
.
_prefix
,
self
.
__dict__
address
=
[
x
for
x
in
utils
.
parse_address
(
address
)
address_list
=
[]
if
x
[
2
]
not
in
self
.
_disable_proto
]
same_country
=
self
.
cache
.
same_country
for
x
in
utils
.
parse_address
(
address
):
if
x
[
2
]
in
self
.
_disable_proto
:
continue
if
same_country
:
family
,
ip
=
resolve
(
*
x
)
my_country
=
self
.
_country
.
get
(
family
)
if
my_country
:
for
ip
in
ip
:
country
=
self
.
_geoiplookup
(
ip
)
if
country
and
(
country
!=
my_country
if
my_country
in
same_country
else
country
in
same_country
):
logging
.
debug
(
'Do not tunnel to %s (%s -> %s)'
,
ip
,
my_country
,
country
)
else
:
address_list
.
append
((
ip
,
x
[
1
],
x
[
2
]))
continue
address_list
.
append
(
x
)
self
.
cache
.
connecting
(
prefix
,
1
)
self
.
cache
.
connecting
(
prefix
,
1
)
if
not
address
:
if
not
address
_list
:
return
False
return
False
logging
.
info
(
'Establishing a connection with %u/%u'
,
logging
.
info
(
'Establishing a connection with %u/%u'
,
int
(
prefix
,
2
),
len
(
prefix
))
int
(
prefix
,
2
),
len
(
prefix
))
with
utils
.
exit
:
with
utils
.
exit
:
iface
=
self
.
_getFreeInterface
(
prefix
)
iface
=
self
.
_getFreeInterface
(
prefix
)
self
.
_connection_dict
[
prefix
]
=
c
=
Connection
(
self
,
address
,
iface
,
prefix
)
self
.
_connection_dict
[
prefix
]
=
c
=
Connection
(
self
,
address_list
,
iface
,
prefix
)
if
self
.
_gateway_manager
is
not
None
:
if
self
.
_gateway_manager
is
not
None
:
for
ip
in
c
:
for
ip
in
c
:
self
.
_gateway_manager
.
add
(
ip
,
True
)
self
.
_gateway_manager
.
add
(
ip
,
True
)
...
@@ -917,6 +995,9 @@ class TunnelManager(BaseTunnelManager):
...
@@ -917,6 +995,9 @@ class TunnelManager(BaseTunnelManager):
family
,
address
=
self
.
_ip_changed
(
ip
)
family
,
address
=
self
.
_ip_changed
(
ip
)
if
address
:
if
address
:
self
.
_address
[
family
]
=
utils
.
dump_address
(
address
)
self
.
_address
[
family
]
=
utils
.
dump_address
(
address
)
if
self
.
_geoiplookup
:
self
.
_updateCountry
(
address
)
self
.
cache
.
my_address
=
';'
.
join
(
self
.
_address
.
itervalues
())
def
broadcastNewVersion
(
self
):
def
broadcastNewVersion
(
self
):
self
.
_babel_dump_new_version
()
self
.
_babel_dump_new_version
()
...
...
re6st/version.py
View file @
d7a4d73f
...
@@ -32,7 +32,7 @@ if dirty:
...
@@ -32,7 +32,7 @@ if dirty:
# they are intended to the network admin.
# they are intended to the network admin.
# Only 'protocol' is important and it must be increased whenever they would be
# Only 'protocol' is important and it must be increased whenever they would be
# a wish to force an update of nodes.
# a wish to force an update of nodes.
protocol
=
3
protocol
=
4
min_protocol
=
1
min_protocol
=
1
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
...
...
setup.py
View file @
d7a4d73f
...
@@ -93,6 +93,9 @@ setup(
...
@@ -93,6 +93,9 @@ setup(
# BBB: use MANIFEST.in only so that egg_info works with very old setuptools
# BBB: use MANIFEST.in only so that egg_info works with very old setuptools
include_package_data
=
True
,
include_package_data
=
True
,
install_requires
=
[
'pyOpenSSL >= 0.13'
,
'miniupnpc'
],
install_requires
=
[
'pyOpenSSL >= 0.13'
,
'miniupnpc'
],
extras_require
=
{
'geoip'
:
[
'geoip2'
],
},
#dependency_links = [
#dependency_links = [
# "http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.7.20120714.tar.gz#egg=miniupnpc-1.7",
# "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