mirror of
https://github.com/evilsocket/opensnitch.git
synced 2025-03-04 08:34:40 +01:00
Fix n stuff
This commit is contained in:
parent
7caa119361
commit
0c4aa8a1a7
6 changed files with 122 additions and 71 deletions
16
main.py
16
main.py
|
@ -1,14 +1,20 @@
|
|||
#!/usr/bin/python
|
||||
import os
|
||||
import logging
|
||||
|
||||
from opensnitch.packetqueue import PacketQueue
|
||||
logging.basicConfig(format='[%(asctime)s] (%(levelname)s) %(message)s',level=logging.DEBUG)
|
||||
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
|
||||
|
||||
q = PacketQueue()
|
||||
from opensnitch.snitch import Snitch
|
||||
|
||||
snitch = Snitch()
|
||||
|
||||
try:
|
||||
q.start()
|
||||
logging.info( "OpenSnitch running with pid %d." % os.getpid() )
|
||||
snitch.start()
|
||||
except KeyboardInterrupt, e:
|
||||
pass
|
||||
|
||||
print "\n\nStopping ..."
|
||||
logging.info( "Quitting ..." )
|
||||
|
||||
q.stop()
|
||||
snitch.stop()
|
||||
|
|
|
@ -5,10 +5,11 @@ from socket import inet_ntoa
|
|||
|
||||
class Connection:
|
||||
def __init__( self, payload ):
|
||||
self.data = payload.get_data()
|
||||
self.data = payload
|
||||
self.pkt = ip.IP( self.data )
|
||||
self.src_addr = inet_ntoa( self.pkt.src )
|
||||
self.dst_addr = inet_ntoa( self.pkt.dst )
|
||||
self.hostname = None
|
||||
self.src_port = None
|
||||
self.dst_port = None
|
||||
self.proto = None
|
||||
|
|
32
opensnitch/dns.py
Normal file
32
opensnitch/dns.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
import logging
|
||||
from threading import Lock
|
||||
from scapy.all import *
|
||||
|
||||
class DNSCollector:
|
||||
def __init__(self):
|
||||
self.lock = Lock()
|
||||
self.hosts = { '127.0.0.1': 'localhost' }
|
||||
|
||||
def is_dns_response(self, packet):
|
||||
if DNSRR in packet and packet.qd is not None and packet.an is not None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def add_response( self, packet ):
|
||||
with self.lock:
|
||||
hostname = packet.qd.qname
|
||||
address = packet.an.rdata
|
||||
if hostname.endswith('.'):
|
||||
hostname = hostname[:-1]
|
||||
|
||||
logging.debug( "DNS[%s] = %s" % ( address, hostname ) )
|
||||
self.hosts[address] = hostname
|
||||
|
||||
def get_hostname( self, address ):
|
||||
with self.lock:
|
||||
if address in self.hosts:
|
||||
return self.hosts[address]
|
||||
else:
|
||||
logging.debug( "No hostname found for address %s" % address )
|
||||
return address
|
|
@ -1,59 +0,0 @@
|
|||
import os
|
||||
import nfqueue
|
||||
from socket import AF_INET, AF_INET6, inet_ntoa
|
||||
from threading import Lock
|
||||
|
||||
from opensnitch.ui import UI
|
||||
from opensnitch.connection import Connection
|
||||
from opensnitch.rule import Rules
|
||||
|
||||
class PacketQueue:
|
||||
lock = Lock()
|
||||
rules = Rules()
|
||||
fw_rules = ( "OUTPUT -t mangle -m conntrack --ctstate NEW -j NFQUEUE --queue-num 0 --queue-bypass",
|
||||
"INPUT --protocol udp --sport 53 -j NFQUEUE --queue-num 0 --queue-bypass" )
|
||||
|
||||
@staticmethod
|
||||
def get_verdict( c ):
|
||||
verdict = PacketQueue.rules.get_verdict(c)
|
||||
|
||||
if verdict is None:
|
||||
with PacketQueue.lock:
|
||||
( verdict, apply_for_all ) = UI.prompt_user( c.app.name,
|
||||
c.app_path,
|
||||
None,
|
||||
c.dst_addr,
|
||||
c.dst_port,
|
||||
c.proto )
|
||||
PacketQueue.rules.add_rule( c, verdict, apply_for_all )
|
||||
|
||||
return verdict
|
||||
|
||||
@staticmethod
|
||||
def pkt_callback(pkt):
|
||||
conn = Connection(pkt)
|
||||
verd = nfqueue.NF_ACCEPT
|
||||
|
||||
if conn.proto is not None:
|
||||
verd = PacketQueue.get_verdict( conn )
|
||||
|
||||
pkt.set_verdict(verd)
|
||||
return 1
|
||||
|
||||
# TODO: Support IPv6!
|
||||
def __init__( self ):
|
||||
self.q = nfqueue.queue()
|
||||
self.q.set_callback( PacketQueue.pkt_callback )
|
||||
self.q.fast_open(0, AF_INET)
|
||||
self.q.set_queue_maxlen(2*1024)
|
||||
|
||||
def start(self):
|
||||
for r in PacketQueue.fw_rules:
|
||||
os.system( "iptables -I %s" % r )
|
||||
self.q.try_run()
|
||||
|
||||
def stop(self):
|
||||
for r in PacketQueue.fw_rules:
|
||||
os.system( "iptables -D %s" % r )
|
||||
self.q.unbind(AF_INET)
|
||||
self.q.close()
|
71
opensnitch/snitch.py
Normal file
71
opensnitch/snitch.py
Normal file
|
@ -0,0 +1,71 @@
|
|||
import os
|
||||
import logging
|
||||
import nfqueue
|
||||
from socket import AF_INET, AF_INET6, inet_ntoa
|
||||
from threading import Lock
|
||||
from scapy.all import *
|
||||
|
||||
from opensnitch.ui import UI
|
||||
from opensnitch.connection import Connection
|
||||
from opensnitch.dns import DNSCollector
|
||||
from opensnitch.rule import Rules
|
||||
|
||||
class Snitch:
|
||||
IPTABLES_RULES = ( "OUTPUT -t mangle -m conntrack --ctstate NEW -j NFQUEUE --queue-num 0 --queue-bypass", )
|
||||
|
||||
# TODO: Support IPv6!
|
||||
def __init__( self ):
|
||||
self.lock = Lock()
|
||||
self.rules = Rules()
|
||||
self.dns = DNSCollector()
|
||||
self.q = nfqueue.queue()
|
||||
|
||||
self.q.set_callback( self.pkt_callback )
|
||||
self.q.fast_open(0, AF_INET)
|
||||
self.q.set_queue_maxlen(2*1024)
|
||||
|
||||
def get_verdict(self,c):
|
||||
verdict = self.rules.get_verdict(c)
|
||||
|
||||
if verdict is None:
|
||||
with self.lock:
|
||||
c.hostname = self.dns.get_hostname(c.dst_addr)
|
||||
( verdict, apply_for_all ) = UI.prompt_user(c)
|
||||
self.rules.add_rule( c, verdict, apply_for_all )
|
||||
|
||||
return verdict
|
||||
|
||||
def pkt_callback(self,pkt):
|
||||
verd = nfqueue.NF_ACCEPT
|
||||
|
||||
try:
|
||||
data = pkt.get_data()
|
||||
packet = IP(data)
|
||||
|
||||
if self.dns.is_dns_response(packet):
|
||||
self.dns.add_response(packet)
|
||||
|
||||
else:
|
||||
conn = Connection(data)
|
||||
if conn.proto is not None:
|
||||
verd = self.get_verdict( conn )
|
||||
except Exception as e:
|
||||
print e
|
||||
|
||||
pkt.set_verdict(verd)
|
||||
return 1
|
||||
|
||||
def start(self):
|
||||
for r in Snitch.IPTABLES_RULES:
|
||||
logging.debug( "Applying iptables rule '%s'" % r )
|
||||
os.system( "iptables -I %s" % r )
|
||||
|
||||
self.q.try_run()
|
||||
|
||||
def stop(self):
|
||||
for r in Snitch.IPTABLES_RULES:
|
||||
logging.debug( "Deleting iptables rule '%s'" % r )
|
||||
os.system( "iptables -D %s" % r )
|
||||
|
||||
self.q.unbind(AF_INET)
|
||||
self.q.close()
|
|
@ -3,14 +3,14 @@ import nfqueue
|
|||
|
||||
class UI:
|
||||
@staticmethod
|
||||
def prompt_user( app_name, app_path, app_icon, d_addr, d_port, proto ):
|
||||
def prompt_user( c ):
|
||||
title = 'OpenSnitch'
|
||||
msg = "%s (%s) wants to connect to %s on %s port %s" % ( \
|
||||
app_name,
|
||||
app_path,
|
||||
d_addr,
|
||||
proto.upper(),
|
||||
d_port )
|
||||
c.app.name,
|
||||
c.app_path,
|
||||
c.hostname,
|
||||
c.proto.upper(),
|
||||
c.dst_port )
|
||||
choices = [ 'Allow Once',
|
||||
'Allow Forever',
|
||||
'Allow All',
|
||||
|
|
Loading…
Add table
Reference in a new issue