开发者

How to listen to data sent via UDP to IP?

There is a remote system sending data to my server via UDP and I'd like to "capture" this data, it's sent to non-specific ports. I know the sender (IP:Port) but the port they send to is variable.

I have no idea which language this should be done with, but I'm open to any. The server runs CentOS. The end goal is to receive the data and then process it with output via PHP.

(I should clarify the data I have opted to be sent, it's not malicious!)

Edit: I should mention the fact that the p开发者_如何学JAVAort is variable isn't my problem, I don't know how to capture any data sent via UDP to any port, I still need to know how to capture and process the data once I can direct it.


You could just write an iptables rule to forward all traffic from that IP:Port to a given port on your system, and then listen on that port for that data. (You might find the CentOS IPTables manual useful)

If you're talking back to the server you'll have to use the NAT table so the proper rewriting happens on the return path. It may also be convenient to do this in any event, even if not required, since then you won't have to do anything to make your listener not surprised that it is receiving packet data for a port it isn't listening on.

Once you have the traffic landing on a single port, you can write a trivial UDP server implementation, like the one in the PHP manual:

http://us3.php.net/manual/en/function.stream-socket-server.php


You need to use libpcap. With that library it's very straightforward to accomplish what you're trying to.

You can use C/C++ with that library for sure. But I'd guess there are binding for other languages too, since it's a very popular library.


I've been recently doing something similar, checkout this code in python:

#!/usr/bin/python

import socket, sys, io
from struct import *
from time import localtime, strftime

#-------------------------------------------------------------------------------
class ETHHeader: # ethernet header
  def __init__(self, s):
    data = s.read(14)
    hdr = unpack("!6s6sH", data)
    self.destination_addr = data[0:6]  # mac address
    self.source_addr      = data[6:12] # mac address
    self.protocol         = socket.ntohs(hdr[2])

  def src_addr(self):
    return addr_to_str(self.srouce_addr)

  def dst_addr(self):
    return addr_to_str(self.destination_addr)

  def is_IP(self): return self.protocol == 8

  #Convert a string of 6 characters of ethernet address into a dash separated hex string
  def addr_to_str (a) :
      b = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" % (ord(a[0]), ord(a[1]) , ord(a[2]), \
                                         ord(a[3]), ord(a[4]) , ord(a[5]))
      return b

#-------------------------------------------------------------------------------
class IPHeader:
  def __init__(self, s):
    iph = unpack('!BBHHHBBH4s4s', s.read(20))
    self.protocol = iph[6]
    self.src_addr = socket.inet_ntoa(iph[8]);
    self.dst_addr = socket.inet_ntoa(iph[9]);

  def __str__(self):
    return "(" + self.proto() + " " + self.src_addr + " -> " + self.dst_addr + ")"

  def proto(self):
    return { 6: "TCP", 1: "ICMP", 17: "UDP" }.get(self.protocol, "???")

#-------------------------------------------------------------------------------
class UDPHeader:
  def __init__(self, s):
    hdr = unpack("!HHHH", s.read(8))
    self.source_port      = hdr[0]
    self.destination_port = hdr[1]
    self.length           = hdr[2]
    self.checksum         = hdr[3]

#-------------------------------------------------------------------------------
try:
  #s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
  # Using this instead of the above we will get:
  #   Also incoming packets.
  #   Ethernet header as part of the received packet.
  #   TCP, UDP, ...
  s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003))
except socket.error, msg:
  print "Socket could not be created. Error Code : " + str(msg[0]) + ' Message ' + msg[1]
  sys.exit()

#-------------------------------------------------------------------------------
def communication_between_ports(udp_header, ports):
  src = udp_header.source_port
  dst = udp_header.destination_port
  return src in ports and dst in ports

def communication_between_ips(ip_header, ips):
  src = ip_header.src_addr
  dst = ip_header.dst_addr
  return src in ips and dst in ips

#-------------------------------------------------------------------------------

while True:
  packet = s.recvfrom(65535) # buffer size

  data = io.BytesIO(packet[0])
  eth  = ETHHeader(data)

  if not eth.is_IP():
    continue

  iph  = IPHeader(data)
  udph = UDPHeader(data)

  if not communication_between_ips(iph, ["192.168.1.3", "192.168.1.102"]):
    continue

  if iph.proto() != "UDP":
    continue

  ## To filter by port:
  #if udph.source_port != <PORT-YOU-WANT>
  #  continue

  time = localtime()
  timestr = strftime("%H:%M:%S", time)

  a = iph.src_addr
  b = iph.dst_addr
  direction = " -> "

  if a > b:
    tmp = a
    a = b
    b = tmp
    direction = " <- "

  print timestr + ": " + a + str(direction) + b

I'm extracting only the data that I need from each layer (ETH, IP, ...) but you should be able to easily extend it.

Got most of the information from this blog post.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜