10

I would like to make server that listen on UDP port 162 (SNMP trap) and then forwards this traffic to multiple clients. Also important is that the source port & address stays same (address spoofing).

I guess that best tool for this would be Twisted or Scapy or maybe vanilla sockets, only I can't find anything in the documentation for Twisted about source address spoofing/forging.

Any solution for this?

Edit:added bounty, mybe any solution with iptables?

Ib33X
  • 6,764
  • 4
  • 28
  • 30

2 Answers2

7

I am not comfortable with twisted or scapy, but it's quite straightforward to do this with vanilla python sockets. An extra advantage of that is that it will be even more portable. This code works in my limited tests:

#!/usr/bin/python
from socket import *
bufsize = 1024 # Modify to suit your needs
targetHost = "somehost.yourdomain.com"
listenPort = 1123

def forward(data, port):
    print "Forwarding: '%s' from port %s" % (data, port)
    sock = socket(AF_INET, SOCK_DGRAM)
    sock.bind(("localhost", port)) # Bind to the port data came in on
    sock.sendto(data, (targetHost, listenPort))

def listen(host, port):
    listenSocket = socket(AF_INET, SOCK_DGRAM)
    listenSocket.bind((host, port))
    while True:
        data, addr = listenSocket.recvfrom(bufsize)
        forward(data, addr[1]) # data and port

listen("localhost", listenPort)
Benson
  • 22,457
  • 2
  • 40
  • 49
  • One thing I forget to put in first part of question statement that I need source address and port from originating server (so actually server needs to fake source address), can socket do this? – Ib33X Dec 14 '09 at 09:44
  • No, no it can't. I think that the problem you're trying to solve here might be better solved by some iptables rules. Why do you want to do it with python, exactly? – Benson Dec 18 '09 at 03:11
  • Incidentally, I'd be very surprised if you can forge packet headers with twisted; scapy is probably your best bet. I'll have a look and see how hard it is. – Benson Dec 18 '09 at 03:12
  • iptables actually I am not that familiar with iptables so I need to learn new skill to do this in iptables, since I am more found off python I decide to learn how to do it in python, and for now I am not doing great ;) – Ib33X Dec 23 '09 at 09:25
  • Well, the problem is that what you're talking about doing is munging packets. Python is not a good tool for that task. In fact, this is less of a programming challenge and more of a sysadminning challenge. While you could write scapy code that woudl do it, it would be inefficient and slow. This belongs in a firewall ruleset. That said, I'll still see what I can find. – Benson Dec 26 '09 at 07:17
  • You can try using raw sockets to do your spoofing. – piotr Apr 20 '10 at 07:50
  • A good point. I could try throwing together a raw socket example. I still say this question is based on the incorrect assumption that it's a programming problem -- it should really be done with existing firewall software. – Benson Apr 20 '10 at 22:20
  • @Benson: I just fell in a use case to need this in "userspace software" - I am running on a VPS in which I cannot run/setup iptables - and only the IP on this VPS is white listed in a target system I need to access. – jsbueno Aug 30 '12 at 21:55
  • @jsbueno do you have root on the machine? I'm fairly certain you'd need to do this with raw sockets, which you need root for. – Benson Aug 31 '12 at 00:06
  • Yes - I have root on it, though it does use a VM technology (forgot which right now), that shares the kernel with the host and can't load any modules. (therefore I can't use iptables) – jsbueno Sep 04 '12 at 14:57
  • Ahh, ok. In that case, I think it is possible to solve this problem with a raw-socket daemon. Unfortunately, I don't have time to write an example right now. :-( – Benson Sep 08 '12 at 20:39
1

The accepted answer didn't work for me and I end up using A simple TCP redirector in python :

#!/usr/bin/env python

import socket
import threading
import select
import sys

terminateAll = False

class ClientThread(threading.Thread):
    def __init__(self, clientSocket, targetHost, targetPort):
        threading.Thread.__init__(self)
        self.__clientSocket = clientSocket
        self.__targetHost = targetHost
        self.__targetPort = targetPort

    def run(self):
        print "Client Thread started"

        self.__clientSocket.setblocking(0)

        targetHostSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        targetHostSocket.connect((self.__targetHost, self.__targetPort))
        targetHostSocket.setblocking(0)

        clientData = ""
        targetHostData = ""
        terminate = False
        while not terminate and not terminateAll:
            inputs = [self.__clientSocket, targetHostSocket]
            outputs = []

            if len(clientData) > 0:
                outputs.append(self.__clientSocket)

            if len(targetHostData) > 0:
                outputs.append(targetHostSocket)

            try:
                inputsReady, outputsReady, errorsReady = select.select(inputs, outputs, [], 1.0)
            except Exception, e:
                print e
                break

            for inp in inputsReady:
                if inp == self.__clientSocket:
                    try:
                        data = self.__clientSocket.recv(4096)
                    except Exception, e:
                        print e

                    if data != None:
                        if len(data) > 0:
                            targetHostData += data
                        else:
                            terminate = True
                elif inp == targetHostSocket:
                    try:
                        data = targetHostSocket.recv(4096)
                    except Exception, e:
                        print e

                    if data != None:
                        if len(data) > 0:
                            clientData += data
                        else:
                            terminate = True

            for out in outputsReady:
                if out == self.__clientSocket and len(clientData) > 0:
                    bytesWritten = self.__clientSocket.send(clientData)
                    if bytesWritten > 0:
                        clientData = clientData[bytesWritten:]
                elif out == targetHostSocket and len(targetHostData) > 0:
                    bytesWritten = targetHostSocket.send(targetHostData)
                    if bytesWritten > 0:
                        targetHostData = targetHostData[bytesWritten:]

        self.__clientSocket.close()
        targetHostSocket.close()
        print "ClienThread terminating"

if __name__ == '__main__':
    if len(sys.argv) != 5:
        print 'Usage:\n\tpython SimpleTCPRedirector <host> <port> <remote host> <remote port>'
        print 'Example:\n\tpython SimpleTCPRedirector localhost 8080 www.google.com 80'
        sys.exit(0)     

    localHost = sys.argv[1]
    localPort = int(sys.argv[2])
    targetHost = sys.argv[3]
    targetPort = int(sys.argv[4])

    serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    serverSocket.bind((localHost, localPort))
    serverSocket.listen(5)
    print "Waiting for client..."
    while True:
        try:
            clientSocket, address = serverSocket.accept()
        except KeyboardInterrupt:
            print "\nTerminating..."
            terminateAll = True
            break
        ClientThread(clientSocket, targetHost, targetPort).start()

    serverSocket.close()
Pedro Lobito
  • 94,083
  • 31
  • 258
  • 268