首页 > 技术文章 > Python的网络编程[3] -> BOOTP 协议[1] -> BOOTP 的 Python 实现

stacklike 2017-12-30 13:44 原文

BOOTP实现 / BOOTP Implement


目录

  1. BOOTP 的服务器建立过程
  2. BOOTP 的客户端建立过程

 Note: 理论部分请参考文末相关阅读链接

1 BOOTP 的服务器建立过程

服务器建立步骤主要有:

(1)      设定服务器IP,传送ip(offer_ip),服务端口68,客户端口67;

(2)      建立send_socket/UDP,广播模式允许复用,绑定到服务器ip,客户端端口;

(3)      建立主循环,建立recv_socket进行监听广播地址和客户端口;

(4)      Recv_socket进行广播接收,筛选收到的广播报文,对有效报文进行解码;

(5)      解码报文获取相应信息,xid,mac_id等;

(6)      加码回传报文,填入收到的xid,mac_id,server ip,offer ip, 文件名等;

(7)      利用send_socket向68端口以广播形式回复报文;

(8)      判断待传文件是否还有未传送的,是则回到循环等待下一个有效广播请求

Note: BOOTP_CodeC 中的加码实现可参考 BOOTP 加码的 Python 实现部分内容

 1 import socket
 2 import struct
 3 import os
 4 from BOOTP_CodeC import ServerCodeC
 5 SERVERNAME = 'Bootpserver'
 6 
 7 class BOOTPServer():
 8     def __init__(self):
 9         self.server_ip = '127.0.0.1'
10         self.offer_ip = '127.0.0.8'
11         self.server_port = 68   # Respond client via this port
12         self.client_port = 67   # Receive client data via this port
13         self.send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
14         self.send_sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
15         self.send_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
16         #self.send_sock.bind((self.server_ip, self.client_port))
17         self.file_bin = ['secondboot.b3', 'files4.rc']
18 
19     def requestCheck(self, m):
20         if not (
21                 m['op'] == b'\x01' and # OP
22                 m['htype'] == b'\x01' and # HTYPE
23                 m['hlen'] == b'\x06' and # HLEN
24                 m['hops'] == b'\x00' and # HOPS
25                 m['secs'] == [b'\x00', b'\x00'] and # SECS
26                 m['flags'] == [b'\x80', b'\x00'] and   # FLAGS (broadcast)
27                 m['ciaddr'] == '0.0.0.0' and # Client IP Address
28                 m['yiaddr'] == '0.0.0.0' and # Your Client IP Address
29                 m['siaddr'] == '0.0.0.0' and # Server IP
30                 m['giaddr'] == '0.0.0.0'  # Gateway IP
31                 ):
32             return False
33         if not (
34                 m['sname'] == SERVERNAME or
35                 m['sname'] == ''):
36             return False
37         return True
38 
39     def server_start(self):
40         file_index = 0
41         while True:
42             if file_index >= len(self.file_bin):
43                 break
44             self.rec_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
45             self.rec_sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
46             self.rec_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
47             self.rec_sock.bind(('', self.client_port))
48             print('=== Waiting for packet')
49             msg, addr = self.rec_sock.recvfrom(1024)
50             msgBody = ServerCodeC.collect(msg)
51             print('<<< RECV from %s, client ip is %s, xid: %s, mac id: %s' %
52                   (addr, msgBody['ciaddr'], msgBody['xid'], msgBody['chaddr']))
53             if self.requestCheck(msgBody):
54                 print('=== This is a valid message')
55                 offer = ServerCodeC.offer(transaction_id=msgBody['xid'],
56                                           client_ip_offer=self.offer_ip,
57                                           server_ip=self.server_ip,
58                                           client_mac_id=msgBody['chaddr'],
59                                           file_path=self.file_bin[file_index])
60                 self.send_sock.sendto(offer, ('<broadcast>', 68))
61                 print('>>> SEND ("<broadcast>", 68), offer ip "%s", file name is "%s"' %
62                       (self.offer_ip, self.file_bin[file_index]))
63                 file_index += 1
64         print('=== BOOTP server exit')
65 
66 server = BOOTPServer()
67 server.server_start()

2 BOOTP 的客户端建立过程

客户端建立步骤主要有:

(1)      客户端ip未知,服务端口68,客户端口67;

(2)      建立主循环,建立socket/UDP,广播模式允许复用,监听服务端端口;

(3)      广播模式朝客户端口67发送请求报文,请求报文中填入客户端信息,如xid,mac_id等,并等待接收回复报文;

(4)      进行接收等待,若未超时且受到有效报文,则对有效报文进行解码;

(5)      解码报文获取相应信息,确认xid,mac_id与发送时的是否匹配;

(6)      提取报文信息,为后续(TFTP下载启动文件)做准备;

 1 import socket
 2 import binascii
 3 import struct
 4 from BOOTP_CodeC import ClientCodeC
 5 
 6 class BOOTPClient():
 7     def __init__(self):
 8         self.client_ip = '0.0.0.0'
 9         self.broadcast_ip = '255.255.255.255'   # or '<broadcast>'
10         self.server_ip = '127.0.0.1'
11         self.target_port = 67
12         self.source_port = 68
13         ClientCodeC.get_xid_macid()
14 
15     def recv_check(self, m):
16         if not (
17                 m['op'] == b'\x02' and # OP
18                 m['htype'] == b'\x01' and # HTYPE
19                 m['hlen'] == b'\x06' and # HLEN
20                 m['hops'] == b'\x00' and # HOPS
21                 m['secs'] == [b'\x00', b'\x00'] and # SECS
22                 m['flags'] == [b'\x80', b'\x00'] and   # FLAGS (broadcast)
23                 m['xid'] == ClientCodeC.transaction_id and
24                 m['chaddr'] == ClientCodeC.client_mac_id and
25                 len(m['file'])
26         ):
27             return False
28         return True
29 
30     def client_request(self):
31 
32         while True:
33             self.client_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
34             self.client_sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
35             self.client_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
36             self.client_sock.settimeout(5)
37             #self.client_sock.bind((self.server_ip, 68))
38             self.client_sock.bind(('', 68))
39 
40             self.client_sock.sendto(ClientCodeC.request(), ('<broadcast>', self.target_port))
41             print('>>> SEND ("<broadcast>", %d) request command' % self.target_port)
42             try:
43                 data, addr = self.client_sock.recvfrom(1024)
44             except socket.timeout:
45                 print('=== BOOTP client exit')
46                 break
47             msgBody = ClientCodeC.collect(data)
48             print('<<< RECV', addr)
49             if self.recv_check(msgBody):
50                 print('=== This is a valid message')
51                 client_ip = msgBody['yiaddr']
52                 server_name = msgBody['sname']
53                 file_name = msgBody['file']
54                 server_ip = msgBody['siaddr']
55                 print('=== Server ip: %s, server name: %s, file name: %s, get ip address: %s' %
56                       (server_name, server_ip, file_name, client_ip))
57 client = BOOTPClient()
58 client.client_request()


相关阅读


1. BOOTP 基本理论

推荐阅读