Esempio n. 1
0
def _check_nmb(hostname, is_workgroup, is_master):
    return
    global _nmb_ok
    if not _nmb_ok:
        return
    debug2(' > n%d%d: %s' % (is_workgroup, is_master, hostname))
    argv = ['nmblookup'] + ['-M'] * is_master + ['--', hostname]
    try:
        p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null,
                              env=get_env)
        lines = p.stdout.readlines()
        rv = p.wait()
    except OSError:
        _, e = sys.exc_info()[:2]
        log('%r failed: %r' % (argv, e))
        _nmb_ok = False
        return
    if rv:
        log('%r returned %d' % (argv, rv))
        return
    for line in lines:
        m = re.match(r'(\d+\.\d+\.\d+\.\d+) (\w+)<\w\w>\n', line)
        if m:
            g = m.groups()
            (ip, name) = (g[0], g[1].lower())
            debug3('<    %s -> %s' % (name, ip))
            if is_workgroup:
                _enqueue(_check_smb, ip)
            else:
                found_host(name, ip)
                check_host(name)
Esempio n. 2
0
 def recv_udp(listener, bufsize):
     debug3('Accept UDP using socket_ext recvmsg.')
     srcip, data, adata, _ = listener.recvmsg((bufsize, ),
                                              socket.CMSG_SPACE(24))
     dstip = None
     family = None
     for a in adata:
         if a.cmsg_level == socket.SOL_IP and a.cmsg_type == IP_ORIGDSTADDR:
             family, port = struct.unpack('=HH', a.cmsg_data[0:4])
             port = socket.htons(port)
             if family == socket.AF_INET:
                 start = 4
                 length = 4
             else:
                 raise Fatal("Unsupported socket type '%s'" % family)
             ip = socket.inet_ntop(family,
                                   a.cmsg_data[start:start + length])
             dstip = (ip, port)
             break
         elif a.cmsg_level == SOL_IPV6 and a.cmsg_type == IPV6_ORIGDSTADDR:
             family, port = struct.unpack('=HH', a.cmsg_data[0:4])
             port = socket.htons(port)
             if family == socket.AF_INET6:
                 start = 8
                 length = 16
             else:
                 raise Fatal("Unsupported socket type '%s'" % family)
             ip = socket.inet_ntop(family,
                                   a.cmsg_data[start:start + length])
             dstip = (ip, port)
             break
     return (srcip, dstip, data[0])
Esempio n. 3
0
def udp_done(chan, data, method, sock, dstip):
    (src, srcport, data) = data.split(b",", 2)
    srcip = (src, int(srcport))
    debug3('doing send from %r to %r' % (
        srcip,
        dstip,
    ))
    method.send_udp(sock, srcip, dstip, data)
Esempio n. 4
0
def _check_dns(hostname):
    debug2(' > dns: %s' % hostname)
    try:
        ip = socket.gethostbyname(hostname)
        debug3('<    %s' % ip)
        check_host(ip)
        found_host(hostname, ip)
    except (socket.gaierror, UnicodeError):
        pass
Esempio n. 5
0
def _check_smb(hostname):
    return
    global _smb_ok
    if not _smb_ok:
        return
    debug2(' > smb: %s' % hostname)
    argv = ['smbclient', '-U', '%', '-L', hostname]
    try:
        p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null,
                              env=get_env())
        lines = p.stdout.readlines()
        p.wait()
    except OSError:
        _, e = sys.exc_info()[:2]
        log('%r failed: %r' % (argv, e))
        _smb_ok = False
        return

    lines.reverse()

    # junk at top
    while lines:
        line = lines.pop().strip()
        if re.match(r'Server\s+', line):
            break

    # server list section:
    #    Server   Comment
    #    ------   -------
    while lines:
        line = lines.pop().strip()
        if not line or re.match(r'-+\s+-+', line):
            continue
        if re.match(r'Workgroup\s+Master', line):
            break
        words = line.split()
        hostname = words[0].lower()
        debug3('<    %s' % hostname)
        check_host(hostname)

    # workgroup list section:
    #   Workgroup  Master
    #   ---------  ------
    while lines:
        line = lines.pop().strip()
        if re.match(r'-+\s+', line):
            continue
        if not line:
            break
        words = line.split()
        (workgroup, hostname) = (words[0].lower(), words[1].lower())
        debug3('<    group(%s) -> %s' % (workgroup, hostname))
        check_host(hostname)
        check_workgroup(workgroup)

    if lines:
        assert(0)
Esempio n. 6
0
def _check_revdns(ip):
    debug2(' > rev: %s' % ip)
    try:
        r = socket.gethostbyaddr(ip)
        debug3('<    %s' % r[0])
        check_host(r[0])
        found_host(r[0], ip)
    except (socket.herror, UnicodeError):
        pass
Esempio n. 7
0
def _nb_clean(func, *args):
    try:
        return func(*args)
    except OSError:
        _, e = sys.exc_info()[:2]
        if e.errno not in (errno.EWOULDBLOCK, errno.EAGAIN):
            raise
        else:
            debug3('%s: err was: %s' % (func.__name__, e))
            return None
Esempio n. 8
0
 def recv_udp(listener, bufsize):
     debug3('Accept UDP python using recvmsg.')
     data, ancdata, _, srcip = listener.recvmsg(4096, socket.CMSG_SPACE(4))
     dstip = 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)
Esempio n. 9
0
 def recv_udp(listener, bufsize):
     debug3('Accept UDP using socket_ext recvmsg.')
     srcip, data, adata, _ = listener.recvmsg((bufsize, ),
                                              socket.CMSG_SPACE(4))
     dstip = 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, a.cmsg_data[0:4])
             dstip = (ip, port)
             break
     return (srcip, dstip, data[0])
Esempio n. 10
0
 def __init__(self, rsock, wsock, connect_to=None, peername=None):
     global _swcount
     _swcount += 1
     debug3('creating new SockWrapper (%d now exist)' % _swcount)
     self.exc = None
     self.rsock = rsock
     self.wsock = wsock
     self.shut_read = self.shut_write = False
     self.buf = []
     self.connect_to = connect_to
     self.peername = peername or _try_peername(self.rsock)
     self.try_connect()
Esempio n. 11
0
def get_auto_method():
    debug3("Selecting a method automatically...")
    # Try these methods, in order:
    methods_to_try = ["nat", "nft", "pf", "ipfw"]
    for m in methods_to_try:
        method = get_method(m)
        if method.is_supported():
            debug3("Method '%s' was automatically selected." % m)
            return method

    raise Fatal("Unable to automatically find a supported method. Check that "
                "the appropriate programs are in your PATH. We tried "
                "methods: %s" % str(methods_to_try))
Esempio n. 12
0
def _check_etc_hosts():
    debug2(' > hosts')
    for line in open('/etc/hosts'):
        line = re.sub(r'#.*', '', line)
        words = line.strip().split()
        if not words:
            continue
        ip = words[0]
        names = words[1:]
        if _is_ip(ip):
            debug3('<    %s %r' % (ip, names))
            for n in names:
                check_host(n)
                found_host(n, ip)
Esempio n. 13
0
def _check_netstat():
    debug2(' > netstat')
    argv = ['netstat', '-n']
    try:
        p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null,
                              env=get_env())
        content = p.stdout.read().decode("ASCII")
        p.wait()
    except OSError:
        _, e = sys.exc_info()[:2]
        log('%r failed: %r' % (argv, e))
        return

    for ip in re.findall(r'\d+\.\d+\.\d+\.\d+', content):
        debug3('<    %s' % ip)
        check_host(ip)
Esempio n. 14
0
def expire_connections(now, mux):
    remove = []
    for chan, timeout in dnsreqs.items():
        if timeout < now:
            debug3('expiring dnsreqs channel=%d' % chan)
            remove.append(chan)
            del mux.channels[chan]
    for chan in remove:
        del dnsreqs[chan]
    debug3('Remaining DNS requests: %d' % len(dnsreqs))

    remove = []
    for peer, (chan, timeout) in udp_by_src.items():
        if timeout < now:
            debug3('expiring UDP channel channel=%d peer=%r' % (chan, peer))
            mux.send(chan, ssnet.CMD_UDP_CLOSE, b'')
            remove.append(peer)
            del mux.channels[chan]
    for peer in remove:
        del udp_by_src[peer]
    debug3('Remaining UDP channels: %d' % len(udp_by_src))
Esempio n. 15
0
 def try_connect(self):
     if self.connect_to and self.shut_write:
         self.noread()
         self.connect_to = None
     if not self.connect_to:
         return  # already connected
     self.rsock.setblocking(False)
     debug3('%r: trying connect to %r' % (self, self.connect_to))
     try:
         self.rsock.connect(self.connect_to)
         # connected successfully (Linux)
         self.connect_to = None
     except socket.error:
         _, e = sys.exc_info()[:2]
         debug3('%r: connect result: %s' % (self, e))
         if e.args[0] == errno.EINVAL:
             # this is what happens when you call connect() on a socket
             # that is now connected but returned EINPROGRESS last time,
             # on BSD, on python pre-2.5.1.  We need to use getsockopt()
             # to get the "real" error.  Later pythons do this
             # automatically, so this code won't run.
             realerr = self.rsock.getsockopt(socket.SOL_SOCKET,
                                             socket.SO_ERROR)
             e = socket.error(realerr, os.strerror(realerr))
             debug3('%r: fixed connect result: %s' % (self, e))
         if e.args[0] in [errno.EINPROGRESS, errno.EALREADY]:
             pass  # not connected yet
         elif e.args[0] == 0:
             # connected successfully (weird Linux bug?)
             # Sometimes Linux seems to return EINVAL when it isn't
             # invalid.  This *may* be caused by a race condition
             # between connect() and getsockopt(SO_ERROR) (ie. it
             # finishes connecting in between the two, so there is no
             # longer an error).  However, I'm not sure of that.
             #
             # I did get at least one report that the problem went away
             # when we added this, however.
             self.connect_to = None
         elif e.args[0] == errno.EISCONN:
             # connected successfully (BSD)
             self.connect_to = None
         elif e.args[0] in NET_ERRS + [errno.EACCES, errno.EPERM]:
             # a "normal" kind of error
             self.connect_to = None
             self.seterr(e)
         else:
             raise  # error we've never heard of?!  barf completely.
Esempio n. 16
0
 def recv_udp(listener, bufsize):
     debug3('Accept UDP using recvfrom.')
     data, srcip = listener.recvfrom(bufsize)
     return (srcip, None, data)
Esempio n. 17
0
def main(latency_control, latency_buffer_size, auto_hosts, to_nameserver,
         auto_nets):
    try:
        helpers.logprefix = ' s: '
        debug1('Starting server with Python version %s'
               % platform.python_version())

        debug1('latency control setting = %r' % latency_control)
        if latency_buffer_size:
            import tshuttle.ssnet as ssnet
            ssnet.LATENCY_BUFFER_SIZE = latency_buffer_size

        # synchronization header
        sys.stdout.write('\0\0SSHUTTLE0001')
        sys.stdout.flush()

        handlers = []
        mux = Mux(sys.stdin, sys.stdout)
        handlers.append(mux)

        debug1('auto-nets:' + str(auto_nets))
        if auto_nets:
            routes = list(list_routes())
            debug1('available routes:')
            for r in routes:
                debug1('  %d/%s/%d' % r)
        else:
            routes = []

        routepkt = ''
        for r in routes:
            routepkt += '%d,%s,%d\n' % r
        mux.send(0, ssnet.CMD_ROUTES, b(routepkt))

        hw = Hostwatch()
        hw.leftover = b('')

        def hostwatch_ready(sock):
            assert(hw.pid)
            content = hw.sock.recv(4096)
            if content:
                lines = (hw.leftover + content).split(b('\n'))
                if lines[-1]:
                    # no terminating newline: entry isn't complete yet!
                    hw.leftover = lines.pop()
                    lines.append(b(''))
                else:
                    hw.leftover = b('')
                mux.send(0, ssnet.CMD_HOST_LIST, b('\n').join(lines))
            else:
                raise Fatal('hostwatch process died')

        def got_host_req(data):
            if not hw.pid:
                (hw.pid, hw.sock) = start_hostwatch(
                        data.decode("ASCII").strip().split(), auto_hosts)
                handlers.append(Handler(socks=[hw.sock],
                                        callback=hostwatch_ready))
        mux.got_host_req = got_host_req

        def new_channel(channel, data):
            (family, dstip, dstport) = data.decode("ASCII").split(',', 2)
            family = int(family)
            # AF_INET is the same constant on Linux and BSD but AF_INET6
            # is different. As the client and server can be running on
            # different platforms we can not just set the socket family
            # to what comes in the wire.
            if family != socket.AF_INET:
                family = socket.AF_INET6
            dstport = int(dstport)
            outwrap = ssnet.connect_dst(family, dstip, dstport)
            handlers.append(Proxy(MuxWrapper(mux, channel), outwrap))
        mux.new_channel = new_channel

        dnshandlers = {}

        def dns_req(channel, data):
            debug2('Incoming DNS request channel=%d.' % channel)
            h = DnsProxy(mux, channel, data, to_nameserver)
            handlers.append(h)
            dnshandlers[channel] = h
        mux.got_dns_req = dns_req

        udphandlers = {}

        def udp_req(channel, cmd, data):
            debug2('Incoming UDP request channel=%d, cmd=%d' %
                   (channel, cmd))
            if cmd == ssnet.CMD_UDP_DATA:
                (dstip, dstport, data) = data.split(b(','), 2)
                dstport = int(dstport)
                debug2('is incoming UDP data. %r %d.' % (dstip, dstport))
                h = udphandlers[channel]
                h.send((dstip, dstport), data)
            elif cmd == ssnet.CMD_UDP_CLOSE:
                debug2('is incoming UDP close')
                h = udphandlers[channel]
                h.ok = False
                del mux.channels[channel]

        def udp_open(channel, data):
            debug2('Incoming UDP open.')
            family = int(data)
            mux.channels[channel] = lambda cmd, data: udp_req(channel, cmd,
                                                              data)
            if channel in udphandlers:
                raise Fatal('UDP connection channel %d already open' %
                            channel)
            else:
                h = UdpProxy(mux, channel, family)
                handlers.append(h)
                udphandlers[channel] = h
        mux.got_udp_open = udp_open

        while mux.ok:
            if hw.pid:
                assert(hw.pid > 0)
                (rpid, rv) = os.waitpid(hw.pid, os.WNOHANG)
                if rpid:
                    raise Fatal(
                        'hostwatch exited unexpectedly: code 0x%04x' % rv)

            ssnet.runonce(handlers, mux)
            if latency_control:
                mux.check_fullness()

            if dnshandlers:
                now = time.time()
                remove = []
                for channel, h in dnshandlers.items():
                    if h.timeout < now or not h.ok:
                        debug3('expiring dnsreqs channel=%d' % channel)
                        remove.append(channel)
                        h.ok = False
                for channel in remove:
                    del dnshandlers[channel]
            if udphandlers:
                remove = []
                for channel, h in udphandlers.items():
                    if not h.ok:
                        debug3('expiring UDP channel=%d' % channel)
                        remove.append(channel)
                        h.ok = False
                for channel in remove:
                    del udphandlers[channel]

    except Fatal as e:
        log('fatal: %s' % e)
        sys.exit(99)
Esempio n. 18
0
 def add_rules(anchor, rules):
     assert isinstance(rules, bytes)
     debug3("rules:\n" + rules.decode("ASCII"))
     pfctl('-a %s -f /dev/stdin' % anchor, rules)
Esempio n. 19
0
def dns_done(chan, data, method, sock, srcip, dstip, mux):
    debug3('dns_done: channel=%d src=%r dst=%r' % (chan, srcip, dstip))
    del mux.channels[chan]
    del dnsreqs[chan]
    method.send_udp(sock, srcip, dstip, data)