Example #1
0
def send_packet(packet, user, to_server):
    """Takes packet, user object and whether to send to server (as though from user) or vice versa.
	Simulates that kind of packet having been recived and passes it on as normal,
	ie. a packet still goes through the whole list of plugins.
	"""
    packets = handle_packet(packet, user, to_server)

    try:
        out_bytestr = "".join([pack(packet, to_server) for packet in packets])
    except:  # Undefined exception inherited from packet_decoder
        logging.exception(
            "Bad packet object while packing generated packet %s %s: %s", "from" if to_server else "to", user, packet
        )
        raise  # Will be caught as a failure of the plugin sending it.

    fd = user.srv_sock if to_server else user.user_sock
    write_buf = send_buffers.get(fd, "")
    write_buf += out_bytestr
    send_buffers[fd] = write_buf
Example #2
0
def main():

    global listener, ticks
    listener = socket()
    listener.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    listener.bind(LISTEN_ADDR)
    listener.listen(128)
    listener.setblocking(0)

    logging.basicConfig(filename=LOG_FILE, level=LOG_LEVEL, format=LOG_FORMAT)
    if DEBUG:
        debug_handler = logging.StreamHandler()  # defaults to stderr
        debug_handler.setFormatter(logging.Formatter(LOG_FORMAT))
        debug_handler.setLevel(logging.DEBUG)
        logging.root.addHandler(debug_handler)

    logging.info("Starting up")
    if PASSTHROUGH:
        passthrough_log = open(PASSTHROUGH_LOG_FILE, "w")

    import helpers  # Hax before import does important hax

    helpers.active_users = active_users
    helpers.send_packet = send_packet

    from plugins import plugins as _plugins  # Lazy import prevents circular references

    global plugins
    plugins = _plugins
    for plugin in plugins[:]:  # Note that x[:] is a copy of x
        try:
            logging.debug("Loading plugin: %s", plugin)
            if hasattr(plugin, "on_start"):
                plugin.on_start()
        except:
            logging.exception("Error initialising plugin %s", plugin)
            plugins.remove(plugin)

    if not DEBUG:
        print "proxy: Daemonising..."
        daemonise()
        sys.stdout.close()
        sys.stderr.close()

    logging.debug("Started up")

    def add_tick(sig, frame):
        global ticks
        ticks += 1

    signal.signal(signal.SIGALRM, add_tick)
    signal.setitimer(signal.ITIMER_REAL, TICK_INTERVAL, TICK_INTERVAL)

    try:
        while 1:

            while ticks:
                handle_tick()
                ticks -= 1

            try:
                r, w, x = select(conn_map.keys() + [listener], send_buffers.keys(), [])
            except select_error, ex:
                ex_errno, ex_msg = ex.args
                if ex_errno == errno.EINTR:
                    continue  # This lets us handle any tick that may have been queued and retry
                raise

            dead = []  # Keeps track of fds in r, w that get dropped, so we know when not to bother.

            for fd in w:
                if fd in dead:
                    logging.debug("fd already down - skipping")
                    continue

                buf = send_buffers[fd]

                try:
                    n = fd.send(buf[:MAX_SEND])
                except socket_error, ex:
                    if ex.errno == errno.EINTR:
                        n = 0
                    elif ex.errno in (errno.ECONNRESET, errno.EPIPE, errno.ENETDOWN, errno.ENETUNREACH, errno.ENOBUFS):
                        # These are all socket failure conditions, drop the connection
                        user = user_map[fd]
                        if (
                            ex.errno == errno.ECONNRESET and fd in usersocks
                        ):  # User CONNRESET is ok, means user closed program or lost conn. Server CONNRESET is NOT.
                            logging.info("Connection from %s closed by connection reset", user)
                        else:
                            logging.warning(
                                "Dropping connection for %s due to send error to %s",
                                user,
                                "user" if fd in user_socks else "server",
                                exc_info=1,
                            )
                        dead += [fd, conn_map[fd]]
                        drop_connection(user)
                        continue
                    else:
                        raise

                assert n <= len(buf)
                if n < len(buf):
                    send_buffers[fd] = buf[n:]
                else:
                    del send_buffers[fd]

            for fd in r:
                if fd in dead:
                    logging.debug("fd already down - skipping")
                    continue

                if fd is listener:
                    new_connection()
                    continue

                buf = read_buffers[fd]
                to_server = fd in user_socks
                user = user_map[fd]

                logging.debug("Buffer before read: length %d", len(buf))
                try:
                    read = fd.recv(MAX_RECV)
                except socket_error, ex:
                    if ex.errno == errno.EINTR:
                        continue
                    if ex.errno in (errno.ECONNRESET, errno.ETIMEDOUT, errno.ENOBUFS, errno.ENOMEM):
                        # These are all socket failure conditions, drop the connection
                        logging.warning(
                            "Dropping connection for %s due to recv error from %s",
                            user,
                            "user" if to_server else "server",
                            exc_info=1,
                        )
                        dead += [fd, conn_map[fd]]
                        drop_connection(user)
                        continue
                if not read:
                    # Empty read means EOF
                    if to_server:
                        logging.info("Connection from %s closed", user)
                    else:
                        logging.info("Server connection for %s closed", user)
                    dead += [fd, conn_map[fd]]
                    drop_connection(user)
                    continue

                    # logging.debug("Read %s server for %s: %s", "to" if to_server else "from", user, repr(read))
                buf += read
                logging.debug("Buffer after read: length %d", len(buf))

                # Decode as many packets as we can
                while 1:

                    if PASSTHROUGH:
                        if not buf:
                            break
                        out_bytestr = buf
                        logging.info("Passing through %s", repr(buf))
                        passthrough_log.write(buf)
                        passthrough_log.flush()
                        buf = ""
                    else:

                        try:
                            packet, buf = unpack(buf, to_server)
                        except:  # Undefined exception inherited from packet_decoder
                            logging.exception(
                                "Bad packet %s %s:\n%s", "from" if to_server else "to", user, hexdump(buf)
                            )
                            logging.warning(
                                "Dropping connection for %s due to bad packet from %s",
                                user,
                                "user" if to_server else "server",
                            )
                            dead += [fd, conn_map[fd]]
                            drop_connection(user)
                            break
                        if packet is None:
                            # Couldn't decode, need more read first - we're done here.
                            break

                            # logging.debug("%s server for %s: %s", "to" if to_server else "from", user, packet)

                        packets = handle_packet(packet, user, to_server)
                        packed = []
                        for packet in packets:
                            try:
                                packed.append(pack(packet, to_server))
                            except:  # Undefined exception inherited from packet_decoder
                                logging.warning(
                                    "Bad packet object while packing packet %s %s: %s",
                                    "from" if to_server else "to",
                                    user,
                                    packet,
                                    exc_info=1,
                                )

                        out_bytestr = "".join(packed)

                        # Append resulting bytestr to write buffer, to be sent later.
                    send_fd = conn_map[fd]
                    write_buf = send_buffers.get(send_fd, "")
                    write_buf += out_bytestr
                    send_buffers[send_fd] = write_buf

                if fd not in dead:
                    logging.debug("Buffer after decode: length %d", len(buf))
                    read_buffers[fd] = buf