renaming things for distutils
This commit is contained in:
parent
2a8fb43dd5
commit
4e9dbe6e92
30
README
30
README
@ -52,26 +52,26 @@ Some History:
|
||||
cryptography to /simplify/ the initial port knocking concept,
|
||||
rather than making it more complex.
|
||||
|
||||
knockknock Overview:
|
||||
knocknock Overview:
|
||||
|
||||
So here's how knockknock works:
|
||||
So here's how knocknock works:
|
||||
|
||||
* Servers run the python app 'knockknock-daemon', and clients
|
||||
* Servers run the python app 'knocknock-daemon', and clients
|
||||
open ports on those servers by running the python app
|
||||
'knockknock'
|
||||
'knocknock'
|
||||
|
||||
* 'knockknock-daemon' simply tails kern.log. It doesn't bind to
|
||||
* 'knocknock-daemon' simply tails kern.log. It doesn't bind to
|
||||
any sockets, load libpcap and inspect every packet, or send
|
||||
anything onto the network at all.
|
||||
|
||||
* When you want to open a port from a client, you run
|
||||
'knockknock', which sends a /single/ SYN packet to the server.
|
||||
'knocknock', which sends a /single/ SYN packet to the server.
|
||||
The packet's IP and TCP headers are encoded to represent an
|
||||
IND-CCA secure encrypted request to open a specified port from
|
||||
the source IP address.
|
||||
|
||||
* Fields from this packet are logged to kern.log and processed
|
||||
by 'knockknock-daemon', which validates them.
|
||||
by 'knocknock-daemon', which validates them.
|
||||
|
||||
* You connect from the client to the now-open port on the
|
||||
server.
|
||||
@ -87,26 +87,26 @@ knockknock Overview:
|
||||
evesdropping, replay attacks, and all known forms of cryptanalysis
|
||||
against IND-CCA secure schemes.
|
||||
|
||||
Why Is knockknock Secure?
|
||||
Why Is knocknock Secure?
|
||||
|
||||
* The knockknock-daemon code is very simple, and is written in
|
||||
* The knocknock-daemon code is very simple, and is written in
|
||||
python (a 'safe' language). The code is concise enough to be
|
||||
easily audited, and doesn't make use of any crazy libraries like
|
||||
libpcap.
|
||||
|
||||
* While knockknock-daemon needs root priviledges to adjust
|
||||
* While knocknock-daemon needs root priviledges to adjust
|
||||
iptables rules, it employs privilege separation to isolate the
|
||||
code that actually runs as root to ~15 lines. So even though
|
||||
the entire code base is very small and very simple, the only
|
||||
part of the code actually running with root privilges is even
|
||||
smaller and even simpler. When you run knockknock-daemon, it
|
||||
smaller and even simpler. When you run knocknock-daemon, it
|
||||
will fork out the privileged code and drop privilges everywhere
|
||||
else before processing knockknock requests.
|
||||
else before processing knocknock requests.
|
||||
|
||||
* The communication protocol is a simple IND-CCA secure encryption
|
||||
scheme that uses standard, contemporary, cryptographic
|
||||
constructions. An observer watching packets is not given any
|
||||
indication that the SYN packet transmitted by 'knockknock' is a
|
||||
indication that the SYN packet transmitted by 'knocknock' is a
|
||||
port knocking request, but even if they knew, there would be no
|
||||
way for them to determine which port was requested to open.
|
||||
Replaying the knock request later does them no good, and in fact
|
||||
@ -131,9 +131,9 @@ Why Is This Even Necessary?
|
||||
have?
|
||||
|
||||
The name of the game is to isolate, compartmentalize, and /expose
|
||||
running services as little as possible/. That's where knockknock
|
||||
running services as little as possible/. That's where knocknock
|
||||
comes in. Given that your network services are insecure, you want
|
||||
to expose as few of them to the world as possible. I offer
|
||||
knockknock as a possible solution to minimizing exposure.
|
||||
knocknock as a possible solution to minimizing exposure.
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
"""knockknock-daemon implements Moxie Marlinspike's port knocking protocol."""
|
||||
"""knocknock3-daemon implements Moxie Marlinspike's port knocking protocol."""
|
||||
|
||||
__author__ = "Moxie Marlinspike"
|
||||
__email__ = "moxie@thoughtcrime.org"
|
||||
@ -25,27 +25,27 @@ USA
|
||||
|
||||
import os, sys, pwd, grp
|
||||
|
||||
from knockknock.LogEntry import LogEntry
|
||||
from knockknock.LogFile import LogFile
|
||||
from knockknock.Profiles import Profiles
|
||||
from knockknock.PortOpener import PortOpener
|
||||
from knockknock.DaemonConfiguration import DaemonConfiguration
|
||||
from knockknock.KnockWatcher import KnockWatcher
|
||||
from knocknock3.LogEntry import LogEntry
|
||||
from knocknock3.LogFile import LogFile
|
||||
from knocknock3.Profiles import Profiles
|
||||
from knocknock3.PortOpener import PortOpener
|
||||
from knocknock3.DaemonConfiguration import DaemonConfiguration
|
||||
from knocknock3.KnockWatcher import KnockWatcher
|
||||
|
||||
import knockknock.daemonize
|
||||
import knocknock3.daemonize
|
||||
|
||||
def checkPrivileges():
|
||||
if (not os.geteuid() == 0):
|
||||
print("Sorry, you have to run knockknock-daemon as root.")
|
||||
print("Sorry, you have to run knocknock3-daemon as root.")
|
||||
sys.exit(3)
|
||||
|
||||
def checkConfiguration():
|
||||
if (not os.path.isdir('/etc/knockknock.d/')):
|
||||
print("/etc/knockknock.d/ does not exist. You need to setup your profiles first..")
|
||||
if (not os.path.isdir('/etc/knocknock3.d/')):
|
||||
print("/etc/knocknock3.d/ does not exist. You need to setup your profiles first..")
|
||||
sys.exit(3)
|
||||
|
||||
if (not os.path.isdir('/etc/knockknock.d/profiles/')):
|
||||
print("/etc/knockknock.d/profiles/ does not exist. You need to setup your profiles first...")
|
||||
if (not os.path.isdir('/etc/knocknock3.d/profiles/')):
|
||||
print("/etc/knocknock3.d/profiles/ does not exist. You need to setup your profiles first...")
|
||||
sys.exit(3)
|
||||
|
||||
def dropPrivileges():
|
||||
@ -73,13 +73,13 @@ def main(argv):
|
||||
checkPrivileges()
|
||||
checkConfiguration()
|
||||
|
||||
profiles = Profiles('/etc/knockknock.d/profiles/')
|
||||
config = DaemonConfiguration('/etc/knockknock.d/config')
|
||||
profiles = Profiles('/etc/knocknock3.d/profiles/')
|
||||
config = DaemonConfiguration('/etc/knocknock3.d/config')
|
||||
|
||||
if (profiles.isEmpty()):
|
||||
print('WARNING: Running knockknock-daemon without any active profiles.')
|
||||
print('WARNING: Running knocknock3-daemon without any active profiles.')
|
||||
|
||||
knockknock.daemonize.createDaemon()
|
||||
knocknock3.daemonize.createDaemon()
|
||||
|
||||
input, output = os.pipe()
|
||||
pid = os.fork()
|
@ -23,14 +23,14 @@ USA
|
||||
"""
|
||||
|
||||
import os, sys
|
||||
from knockknock.Profiles import Profiles
|
||||
from knockknock.Profile import Profile
|
||||
from knocknock3.Profiles import Profiles
|
||||
from knocknock3.Profile import Profile
|
||||
|
||||
DAEMON_DIR = '/etc/knockknock.d/'
|
||||
DAEMON_DIR = '/etc/knocknock3.d/'
|
||||
PROFILES_DIR = DAEMON_DIR + 'profiles/'
|
||||
|
||||
def usage():
|
||||
print("knockknock-genprofile <profileName> <knockPort>")
|
||||
print("knocknock3-genprofile <profileName> <knockPort>")
|
||||
sys.exit(3)
|
||||
|
||||
def checkProfile(profileName):
|
@ -24,10 +24,10 @@ USA
|
||||
|
||||
import os, sys, asyncore, socket
|
||||
|
||||
from knockknock.Profiles import Profiles
|
||||
from knockknock.proxy.SocksRequestHandler import SocksRequestHandler
|
||||
from knocknock3.Profiles import Profiles
|
||||
from knocknock3.proxy.SocksRequestHandler import SocksRequestHandler
|
||||
|
||||
import knockknock.daemonize
|
||||
import knocknock3.daemonize
|
||||
|
||||
class ProxyServer(asyncore.dispatcher):
|
||||
|
||||
@ -45,26 +45,26 @@ class ProxyServer(asyncore.dispatcher):
|
||||
|
||||
|
||||
def usage():
|
||||
print("knockknock-proxy <listenPort>")
|
||||
print("knocknock3-proxy <listenPort>")
|
||||
sys.exit(3)
|
||||
|
||||
def getProfiles():
|
||||
homedir = os.path.expanduser('~')
|
||||
profiles = Profiles(homedir + '/.knockknock/')
|
||||
profiles = Profiles(homedir + '/.knocknock3/')
|
||||
profiles.resolveNames()
|
||||
|
||||
return profiles
|
||||
|
||||
def checkPrivileges():
|
||||
if not os.geteuid() == 0:
|
||||
print("\nSorry, knockknock-proxy has to be run as root.\n")
|
||||
print("\nSorry, knocknock3-proxy has to be run as root.\n")
|
||||
usage()
|
||||
|
||||
def checkProfiles():
|
||||
homedir = os.path.expanduser('~')
|
||||
|
||||
if not os.path.isdir(homedir + '/.knockknock/'):
|
||||
print("Error: you need to setup your profiles in " + homedir + "/.knockknock/")
|
||||
if not os.path.isdir(homedir + '/.knocknock3/'):
|
||||
print("Error: you need to setup your profiles in " + homedir + "/.knocknock3/")
|
||||
sys.exit(2)
|
||||
|
||||
def main(argv):
|
||||
@ -78,7 +78,7 @@ def main(argv):
|
||||
profiles = getProfiles()
|
||||
server = ProxyServer(int(argv[0]), profiles)
|
||||
|
||||
knockknock.daemonize.createDaemon()
|
||||
knocknock3.daemonize.createDaemon()
|
||||
|
||||
asyncore.loop(use_poll=True)
|
||||
|
@ -26,10 +26,10 @@ import getopt
|
||||
import subprocess
|
||||
|
||||
from struct import *
|
||||
from knockknock.Profile import Profile
|
||||
from knocknock3.Profile import Profile
|
||||
|
||||
def usage():
|
||||
print("Usage: knockknock.py -p <portToOpen> <host>")
|
||||
print("Usage: knocknock3.py -p <portToOpen> <host>")
|
||||
sys.exit(2)
|
||||
|
||||
def parseArguments(argv):
|
||||
@ -60,15 +60,15 @@ def parseArguments(argv):
|
||||
def getProfile(host):
|
||||
homedir = os.path.expanduser('~')
|
||||
|
||||
if not os.path.isdir(homedir + '/.knockknock/'):
|
||||
print("Error: you need to setup your profiles in " + homedir + '/.knockknock/')
|
||||
if not os.path.isdir(homedir + '/.knocknock3/'):
|
||||
print("Error: you need to setup your profiles in " + homedir + '/.knocknock3/')
|
||||
sys.exit(2)
|
||||
|
||||
if not os.path.isdir(homedir + '/.knockknock/' + host):
|
||||
print('Error: profile for host ' + host + ' not found at ' + homedir + '/.knockknock/' + host)
|
||||
if not os.path.isdir(homedir + '/.knocknock3/' + host):
|
||||
print('Error: profile for host ' + host + ' not found at ' + homedir + '/.knocknock3/' + host)
|
||||
sys.exit(2)
|
||||
|
||||
return Profile(homedir + '/.knockknock/' + host)
|
||||
return Profile(homedir + '/.knocknock3/' + host)
|
||||
|
||||
def verifyPermissions():
|
||||
if os.getuid() != 0:
|
@ -29,7 +29,7 @@ class DaemonConfiguration:
|
||||
self.delay = int(parser.get('main', 'delay'))
|
||||
self.window = int(parser.get('main', 'error_window'))
|
||||
except ConfigParser.NoSectionError:
|
||||
print("knockknock-daemon: config file not found, assuming defaults.")
|
||||
print("knocknock3-daemon: config file not found, assuming defaults.")
|
||||
self.delay = 15
|
||||
self.window = 20
|
||||
|
@ -33,7 +33,7 @@ class PortOpener:
|
||||
port = self.stream.readline().rstrip("\n")
|
||||
|
||||
if sourceIP == "" or port == "":
|
||||
syslog.syslog("knockknock.PortOpener: Parent process is closed. Terminating.")
|
||||
syslog.syslog("knocknock3.PortOpener: Parent process is closed. Terminating.")
|
||||
os._exit(4)
|
||||
|
||||
description = 'INPUT -m limit --limit 1/minute --limit-burst 1 -m state --state NEW -p tcp -s ' + sourceIP + ' --dport ' + str(port) + ' -j ACCEPT'
|
||||
@ -50,5 +50,5 @@ class PortOpener:
|
||||
self.stream.write(str(port) + "\n")
|
||||
self.stream.flush()
|
||||
except:
|
||||
syslog.syslog("knockknock: Error, PortOpener process has died. Terminating.")
|
||||
syslog.syslog("knocknock3: Error, PortOpener process has died. Terminating.")
|
||||
os._exit(4)
|
@ -40,16 +40,18 @@ def createDaemon():
|
||||
|
||||
try:
|
||||
pid = os.fork()
|
||||
except(OSError, e):
|
||||
raise Exception("%s [%d]" % (e.strerror, e.errno))
|
||||
except OSError:
|
||||
tb = sys.exc_info()[2]
|
||||
raise Exception("OSError").with_traceback(tb)
|
||||
|
||||
if (pid == 0): # The first child.
|
||||
os.setsid()
|
||||
|
||||
try:
|
||||
pid = os.fork() # Fork a second child.
|
||||
except(OSError, e):
|
||||
raise Exception("%s [%d]" % (e.strerror, e.errno))
|
||||
except OSError:
|
||||
tb = sys.exc_info()[2]
|
||||
raise Exception("OSError").with_traceback(tb)
|
||||
|
||||
if (pid == 0): # The second child.
|
||||
os.chdir(WORKDIR)
|
@ -1,8 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script provides the minimal firewall rules necessary to run
|
||||
# knockknock. Essentially, no connections are allowed, unless they
|
||||
# are authenticated with knockknock.
|
||||
# knocknock. Essentially, no connections are allowed, unless they
|
||||
# are authenticated with knocknock.
|
||||
#
|
||||
# Courtesy: Jake Appelbaum
|
||||
|
||||
@ -25,4 +25,4 @@ $IPTABLES -A REJECTLOG -p tcp -j REJECT --reject-with tcp-reset
|
||||
$IPTABLES -A REJECTLOG -j REJECT
|
||||
|
||||
# Reject all other incoming traffic:
|
||||
$IPTABLES -A INPUT -j REJECTLOG
|
||||
$IPTABLES -A INPUT -j REJECTLOG
|
||||
|
40
setup.py
40
setup.py
@ -2,28 +2,28 @@ import sys, os, shutil
|
||||
from distutils.core import setup, Extension
|
||||
|
||||
if sys.argv[1] != "sdist":
|
||||
shutil.copyfile("knockknock-daemon.py", "knockknock/knockknock-daemon")
|
||||
shutil.copyfile("knockknock-genprofile.py", "knockknock/knockknock-genprofile")
|
||||
shutil.copyfile("knockknock-proxy.py", "knockknock/knockknock-proxy")
|
||||
shutil.copyfile("knockknock.py", "knockknock/knockknock")
|
||||
shutil.copyfile("knocknock3-daemon.py", "knocknock3/knocknock3-daemon")
|
||||
shutil.copyfile("knocknock3-genprofile.py", "knocknock3/knocknock3-genprofile")
|
||||
shutil.copyfile("knocknock3-proxy.py", "knocknock3/knocknock3-proxy")
|
||||
shutil.copyfile("knocknock3.py", "knocknock3/knocknock3")
|
||||
|
||||
setup (name = 'knockknock',
|
||||
setup (name = 'knocknock3',
|
||||
version = '0.8',
|
||||
description = 'A cryptographic single-packet port-knocker.',
|
||||
author = 'Moxie Marlinspike',
|
||||
author_email = 'moxie@thoughtcrime.org',
|
||||
url = 'http://www.thoughtcrime.org/software/knockknock/',
|
||||
url = 'http://www.thoughtcrime.org/software/knocknock/',
|
||||
license = 'GPL',
|
||||
packages = ["knockknock", "knockknock.proxy"],
|
||||
scripts = ['knockknock/knockknock-daemon',
|
||||
'knockknock/knockknock-genprofile',
|
||||
'knockknock/knockknock-proxy',
|
||||
'knockknock/knockknock'],
|
||||
data_files = [("", ["minimal-firewall.sh", "knockknock-daemon.py",
|
||||
"knockknock-genprofile.py", "knockknock-proxy.py",
|
||||
"knockknock.py"]),
|
||||
('share/knockknock', ['README', 'INSTALL', 'COPYING']),
|
||||
('/etc/knockknock.d/', ['config'])]
|
||||
packages = ["knocknock3", "knocknock3.proxy"],
|
||||
scripts = ['knocknock3/knocknock3-daemon',
|
||||
'knocknock3/knocknock3-genprofile',
|
||||
'knocknock3/knocknock3-proxy',
|
||||
'knocknock3/knocknock3'],
|
||||
data_files = [("", ["minimal-firewall.sh", "knocknock3-daemon.py",
|
||||
"knocknock3-genprofile.py", "knocknock3-proxy.py",
|
||||
"knocknock3.py"]),
|
||||
('share/knocknock3', ['README', 'INSTALL', 'COPYING']),
|
||||
('/etc/knocknock3.d/', ['config'])]
|
||||
)
|
||||
|
||||
print("Cleaning up...")
|
||||
@ -32,10 +32,10 @@ if os.path.exists("build/"):
|
||||
shutil.rmtree("build/")
|
||||
|
||||
try:
|
||||
os.remove("knockknock/knockknock-proxy")
|
||||
os.remove("knockknock/knockknock-daemon")
|
||||
os.remove("knockknock/knockknock-genprofile")
|
||||
os.remove("knockknock/knockknock")
|
||||
os.remove("knocknock3/knocknock3-proxy")
|
||||
os.remove("knocknock3/knocknock3-daemon")
|
||||
os.remove("knocknock3/knocknock3-genprofile")
|
||||
os.remove("knocknock3/knocknock3")
|
||||
|
||||
except:
|
||||
pass
|
||||
|
Loading…
Reference in New Issue
Block a user