如何监听通过UDP发送到IP的数据?

时间:2010-11-02 16:58:23

标签: udp

有一个远程系统通过UDP向我的服务器发送数据,我想“捕获”这些数据,它被发送到非特定端口。我知道发件人(IP:端口),但他们发送到的端口是可变的。

我不知道应该使用哪种语言,但我对任何语言都持开放态度。服务器运行CentOS。最终目标是接收数据,然后通过PHP输出处理数据。

(我应该澄清我选择发送的数据,这不是恶意的!)

编辑:我应该提一下端口是可变的这个事实不是我的问题,我不知道如何捕获通过UDP发送到任何任何数据端口,我仍然需要知道如何在我指导数据后捕获和处理数据。

3 个答案:

答案 0 :(得分:2)

您可以编写一个iptables规则来转发来自该IP的所有流量:端口到系统上的给定端口,然后在该端口上侦听该数据。 (您可能会发现CentOS IPTables manual很有用)

如果您正在与服务器通话,则必须使用NAT表,以便在返回路径上进行正确的重写。在任何情况下执行此操作也可能很方便,即使不是必需的,因为这样您就不必做任何事情让听众不会惊讶于它正在接收未侦听的端口的数据包数据。 / p>

在单个端口上进行流量登陆后,您可以编写一个简单的UDP服务器实现,就像PHP手册中的那样:

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

答案 1 :(得分:0)

您需要使用libpcap。通过该库,您可以非常直接地完成您想要的工作。

您可以将 C / C ++ 与该库一起使用。但我猜其他语言也有绑定,因为它是一个非常受欢迎的库。

答案 2 :(得分:0)

我最近做过类似的事情,在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

我只从每个图层中提取我需要的数据(ETH,IP,...),但您应该能够轻松扩展它。

获取this blog post的大部分信息。