Python socket.accept()没有收到任何连接请求

时间:2015-03-30 00:27:07

标签: python linux sockets proxy

我最近刚买了Justin Seitz的 Black Hat Python 这本书,因为我对进入Python并使用网络安全感兴趣。

我在 Kali Linux 中工作,本书中的一个示例是一个简单的TCP代理。我已经编写了一些通过端口连接的脚本,但现在我无法尝试创建与远程服务器(如Google)的连接。

现在,我承认我只是一个Python的新手。我主要使用C ++编程。作为一个披露,我确实将main()函数移动到代码的顶部,以便按执行顺序进行组织。在实际来源中,它位于最底层。

import sys
import socket
import threading
import time
import os

def main():
    if len(sys.argv[1:]) != 5:
        print "Usage: nproxy.py [localhost] [localport] [remotehost] [remoteport] [receive_first]"
        print "Example: nproxy.py 127.0.0.1 5555 ftp.example.com 5555 True"
        sys.exit(0)

    #setup listening parameters
    local_host = sys.argv[1]
    local_port = sys.argv[2]
    #setup remote target
    remote_host = sys.argv[3]
    remote_port = sys.argv[4]
    #this tells our proxy to connect and receive data before sending to the remote host
    receive_first = sys.argv[5]

    if "True" in receive_first:
        receive_first = True
    else:
        receive_first = False

此处的所有内容都是main()函数,可以解析和设置所有参数和变量。

    #spin listening socket
    server_loop(local_host, local_port, remote_host, remote_port, receive_first)

#status class for my timeout function to stop the socket.accept()
class status:
    connected = False

server_loop()函数是我的问题的源函数。它包含将客户端连接到服务器的所有代码。

第一部分只是设置我的服务器套接字以及为自己创建一些执行快捷方式。

def server_loop(local_host, local_port, remote_host, remote_port, receive_first):
    #setup server socket
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    if "@" in local_host:
        local_host = "127.0.0.1"

    if "@" in local_port:
        local_port = remote_port

    local_addr = (local_host, int(local_port))
    remote_addr = (remote_host, int(remote_port))

将服务器绑定到我的本地地址就可以了。我想是在问题开始的while循环期间。

    try:
        server.bind(local_addr)
    except:
        print "[!!] Failed to listen on %s:%d" % local_addr
        print "[!!] Check for other listening sockets or correct permissions."
        sys.exit(0)

    print "[*] Listening on %s:%d" % local_addr
    server.listen(5)

这里启动while循环以保持程序打开以处理传入连接。 tout线程包含用于超时和关闭服务器套接字的代码。

    while True:
        tout = threading.Thread(target=timeout, args=(local_host, local_port))
        tout.start()
        print "[*] Connecting..."

这似乎是我的程序挂起的地方。你看,我不是百分之百确定应该如何处理。在本书中,代码对他来说效果很好,并且将成功从server.accept()返回并将client_socket连接到正确的地址。

然而,在我的执行中,程序在accept()函数处停止,并且永远不会返回任何套接字或地址数据。除非我对accept()函数的理解是错误的,并且代码的设计并未考虑远程服务器。

我不完全确定accept()函数是如何工作的。它是否向主机发送SYN数据包以发起连接请求,或者是只是坐在那里等待的功能,认为主机在首先没有发送SYN的情况下将发送SYN-ACK返回?

        client_socket, addr = server.accept()

        #The timeout function is designed to close the server by feeding     
        #it the localhost address. If this happens, the statement below catches the 
        #program and calls that the server request has timed out.

        if "127.0.0.1" in addr[0]:
            print "[!!] Server connection has timed out."
            sys.exit(0)
        #print out the local connection information
        status.connected = True
        print "[==>] Received incoming connection from %s:%d" % (addr[0], addr[1])

        #start a thread to talk to the remote host

如果server.accept()要正常返回,则client_socket将连接到主机,并在发送和正常接收数据时初始化代理的其余部分。剩下的代码是为了完成,以防我错过了一些至关重要的事情,这实际上是失败的原因。

        proxy_thread = threading.Thread(target=proxy_handler, args=(client_socket, remote_addr, receive_first))
        proxy_thread.start()

def timeout(local_host, local_port):
    t = 5
    while True:
        if status.connected is True:
            break
        if t <= 0:
            wake = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            wake.connect((local_host, int(local_port)))
            break
        time.sleep(0.1)
        t-=0.1


def proxy_handler(client_socket, remote_host, remote_port, receive_first):
    #connect to the remote host
    remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    remote_socket.connect(remote_addr)

    if receive_first:
        remote_buffer = receive_from(remote_socket)
        hexdump(remote_buffer)

        #send it to our response handler
        remote_buffer = response_handler(remote_buffer)

        #if we have data to send to our local client, send it
        if len(remote_buffer):
            print "[<==] Sending %d bytes to localhost." % len(remote_buffer)
            client_socket.send(remote_buffer)

    #now let's loop and read from local
    #send to remote, send to local
    #rinse and repeat
    while True:
        #read from localhost
        local_buffer = receive_from(client_socket)
        if len(local_buffer):
            print "[==>] Received %d bytes from localhost." % len(local_buffer)
            hexdump(local_buffer)

            #send it to our request handler
            local_buffer = request_handler(local_buffer)

            #send off the data to the remote host
            remote_socket.send(local_buffer)
            print "[==>] Sent to remote."

        #receive back a response
        remote_buffer = receive_from(remote_socket)

        if len(remote_buffer):
            print "[<==] Received %d bytes from remote" % len(remote_buffer)
            hexdump(remote_buffer)

            #send to our response handler
            remote_buffer = response_handler(remote_buffer)

            #send the response to the local socket
            client_socket.send(remote_buffer)
            print "[<==] Sent to localhost."

        #if no more data on either side, close the connection
        if not len(local_buffer) or not len(remote_buffer):
            client_socket.close()
            remote_socket.close()
            print "[*] No more data. Closing connections..."
            break

def hexdump(src, length=16):
    result = []
    digits = 4 if isinstance(src, unicode) else 2
    for i in xrange(0, len(src), length):
        s = src[i:i+length]
        hexa = b' '.join(["%0*X" % (digits, ord(x)) for x in s])
        text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s])
        result.append(b"%04X   %-*s   %s" % (i, length*digits + 1), hexa, text)
    print b'\n'.join(result)

def receive_from(connection):
    buffer = ""

    #we set a 2 second timeout; depending on your target, this may need to be adjusted
    connection.settimeout(2)

    try:
        #keep reading into the buffer until there's no more data or we time out
        while True:
            data = connection.recv(4096)
            if not data:
                break
            buffer += data
    except:
        pass
    return buffer

#modify any requests destined for remote host
def request_handler(buffer):
    #perform packet modifications
    return buffer

#modify any responses destined for the localhost
def response_handler(buffer):
    #perform packet modification
    return buffer

main()

当我运行程序时,我使用:sudo python ./nproxy.py @ @ www.google.com 21 True

按顺序调用我的程序,前两个参数是自动连接到localhost地址的快捷方式,以及我们尝试连接的主机端口。在这种情况下,它是21,但我也尝试了80端口,结果相同。我也试过了十几个不同的网站,似乎都没有回复我的连接请求。

如果您有任何建议或帮助,请提前感谢您。

1 个答案:

答案 0 :(得分:1)

您的程序按预期工作,但hexdump中的格式字符串无效且proxy_handler应为proxy_handler(client_socket, remote_addr, receive_first)。我也禁用了超时,因为我在本地使用代理我不希望请求关闭它。以下列方式使用它对我有用:

# Start proxy on local port 12345 and route to google
$ python @ 12345 www.google.com 80 True

# In another terminal, request from the server
# This should print the same as `curl www.google.com`
$ curl 127.0.0.1:1235

我认为你误解了应该做的事情。这句话是主要原因。

  

然而,在我的执行中,程序在accept()函数处停止,并且永远不会返回任何套接字或地址数据。除非我对accept()函数的理解是错误的,并且代码的设计并未考虑远程服务器。

我首先要说套接字上的方法基本上是相应C函数的瘦包装,使用man 2 socketman 2 accept获取比python文档可能提供的更多细节。

要回答您的问题,accept()正在阻止,因为没有客户端。它正在等待另一个程序将SYN数据包发送到它的开放套接字,它将用SYN | ACK响应。这部分都与连接到代理的客户端有关,你似乎认为它涉及远程主机。