[ トップページ ]

« 学習用 Ethernet シミュレータ | メイン | 3D プリンタによる 3D タートル・グラフィクスの Python ライブラリ »

ネットワーク・通信

Python による Linux 上の raw socket 通信

C でプログラムを書くのはつかれる,Python のほうが楽だとおもって,Python による raw socket 通信のデモ・プログラムを書いた. おもったほど容易ではなかったが,ほぼ 1 秒ごとに Ethernet のパケットを送受信するプログラムをしめす. (この項目全体は通常の Creative Commons ライセンスによるが,プログラムは public domain とする. つまり,無制限にコピーしてよい.)

Raw socket の指定は容易だが,ほんとうはさらに promiscuous mode で通信できるようにしたかった. しかし,Python で promiscuous mode をまともに実現するのはけっこうめんどうなようだ. とりあえずはアドレスをしっかり指定するようにしている.

### Ethernet packet sender/receiver (for Linux raw socket) ###
#
# Public domain software
#
# Coded by Yasusi Kanada
# 2014-7-29

import optparse, socket, time, binascii

BUF_SIZE = 1600		# > 1500

ETH_P_ALL = 3		# To receive all Ethernet protocols

# Interface = "eth0"
Interface = "eth1"

host = socket.gethostbyname(socket.gethostname())


### Packet field access ###

def SMAC(packet):
   return binascii.hexlify(packet[6:12]).decode()

def DMAC(packet):
   return binascii.hexlify(packet[0:6]).decode()

def EtherType(packet):
   return binascii.hexlify(packet[12:14]).decode()

def Payload(packet):
   return binascii.hexlify(packet[14:]).decode()


### Packet handler ###

def printPacket(packet, now, message):
   # print(message, len(packet), "bytes  time:", now,
   #       "\n  SMAC:", SMAC(packet), " DMAC:", DMAC(packet),
   #       " Type:", EtherType(packet), "\n  Payload:", Payload(packet)) # !! Python 3 !!
   print message, len(packet), "bytes time:", now, \
       "\n  SMAC:", SMAC(packet), " DMAC:", DMAC(packet), " Type:", \
       EtherType(packet), "\n  Payload:", Payload(packet) # !! Python 2 !!


def terminal():
   # Parse command line
   parser = optparse.OptionParser()
   parser.add_option("--p", "--port", dest = "port", type="int",
                     help = "Local network port id")
   parser.add_option("--lm", "--lmac", "--localMAC", dest = "lmac", type="str",
                     help = "Local MAC address")
   parser.add_option("--rm", "--rmac", "--remoteMAC", dest = "rmac", type="str",
                     help = "Remote MAC address")
   parser.add_option("--receiveOnly", "--receiveonly",
                     dest = "receiveOnly", action = "store_true")
   # parser.add_option("--promiscuous", dest = "promiscuous", action = "store_true")
   parser.set_defaults(lmac = "ffffffffffff", rmac = "ffffffffffff")
   opts, args = parser.parse_args()

   # Open socket
   sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))
   sock.bind((Interface, ETH_P_ALL))
   sock.setblocking(0)

   # Contents of packet to send (constant)
   sendPacket = binascii.unhexlify(opts.rmac) + binascii.unhexlify(opts.lmac) + \
       b'\x88\xb5' + b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'

   # Repeat sending and receiving packets
   interval = 1
   lastTime = time.time()
   while True:
      now = time.time()

      try:
         packet = sock.recv(BUF_SIZE)
      except socket.error:
         pass
      else:
         dmac = DMAC(packet)
         printPacket(packet, now, "Received:")

      if not opts.receiveOnly:
         if now > lastTime + interval:
            sendBytes = sock.send(sendPacket)
            printPacket(sendPacket, now, "Sent:   ")
            lastTime = now
         else:
            time.sleep(0.001001)
      else:
         time.sleep(0.001001)

terminal()

送信するパケットには Ethernet type として 0x88b5 がつき,内容は 0x000102… となるが,これらは容易にかえられる.

これは Python 2 用だが,printPacket のところだけなおす (Python 2 用のコードをコメントアウトして Python 3 用のコードをいかす) と Python 3 でもつかえる. Ethernet では通信の際にインタフェース名を指定する必要があるが,ここでは eth1 を指定している. "Interface" という変数の値をかきかえることで容易に変更できる.

つかいかたはつぎのとおりだ. 上記のプログラムに eterm.py というファイル名がついているとする. かんたんなユニキャストの通信 (送信 + 受信) はつぎのようにする.

python eterm.py --lm 00123456789a --rm 00a987654321

ここで MAC アドレスはかならず手でいれる必要がある. (ifconfig コマンドでしらべてコピーする).

つぎのように受信者のアドレスを指定しないとブロードキャストになる (送信アドレスも省略可能).

python eterm.py --lm 00123456789a 

送信せず受信だけするときはつぎのようにする.

python eterm.py --receiveOnly

プログラムを 2 台のマシンで実行して相互にパケットを送受信することもできるし,片方は受信だけ,もう片方は送受信することで,一方向の通信をすることもできる. 一方向の通信は Ethernet スイッチの機能をたしかめるのに有効だ.

Keywords:

トラックバック

このエントリーのトラックバックURL:
http://www.kanadas.com/mt/mt-tb.cgi/6799

コメントを投稿

このページについて

2014-08-05 19:27 に投稿されたエントリーのページです。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Creative Commons License
このブログは、次のライセンスで保護されています。 クリエイティブ・コモンズ・ライセンス.
Powered by
Movable Type 3.36