Python的网络编程[3] -> BOOTP 协议[0] -> BOOTP 的基本理论
BOOTP协议 / BOOTP Protocol
目录
1. 基本理论 / Basic Theory
BOOTP(Bootstrap Protocol)是一种引导协议,基于RFC951协议,基于UDP协议,也称为自举协议,是DHCP协议的前身。BOOTP用于无盘工作站(类似网吧无盘结构)的局域网中,可以让无盘工作站从一个中心服务器上获得IP地址。通过BOOTP协议可以为局域网中的无盘工作站分配动态IP地址,这样就不需要管理员去为每个用户去设置静态IP地址。
BOOTP使用UDP报文传输,并使用保留端口号67(BOOTP服务器,客户端使用此端口作为目标端口发送请求,通常是广播)和68(BOOTP客户端,服务器使用此端口作为目标端口发送应答)工作。使用BOOTP协议的时候,一般包括Bootstrap Protocol Server(自举协议服务端)和Bootstrap Protocol Client(自举协议客户端)两部分。
2. BOOTP 与 DHCP / BOOTP and DHCP
BOOTP协议(BOOTstrap Protocol): 引导程序协议,是一种C/S协议,克服了RARP协议的两个缺陷,具体表现为:(1)BOOTP协议是一个C/S程序,BOOTP服务器可以位于Internet的任何地方;(2)BOOT协议除了返回IP地址外,还提供其他配置信息(如子网掩码等),这些信息可以记录在BOOTP报文的选项部分。但是BOOTP协议的缺陷也很明显:BOOTP协议是一个静态配置协议。也就是说当客户请求自己的IP地址时,BOOTP服务器就会查找一张(MAC-->IP)的映射表,这种映射关系必须是事先设定好的。也就是说:BOOTP协议中,MAC地址和IP地址之间的绑定关系是静态的,是固定存放在一张表中,除非管理员更改这张表。所以后来就提出了现在耳熟能详的DHCP协议。
DHCP协议(Dynamic Host Configuration Protocal):动态主机配置协议。同BOOTP协议一样,DHCP协议也是基于C/S方式的,DHCP是BOOTP的继承者,并且能够兼容BOOTP。DHCP不仅能够处理静态配置(此时等同于BOOTP协议),而且能够处理动态配置。也就是说,在客户在查找其自己的IP地址时,DHCP服务器中(MAC-->IP)地址可以事先存在,也可以临时分配。换句话说:当客户发送DHCP请求报文时,DHCP服务器服务器先在其数据库中查找该计算机的配置信息。若找到,则返回找到的信息。若找不到,则从服务器的IP地址池中取一个地址分配给该计算机。
3 通信流程 / Communication Flow
芯片中的BOOTP启动代码启动客户端,此时客户端还没有地址,因此客户端以0.0.0.0为本机地址,向255.255.255.255:67广播一个请求报文,服务端接收到请求报文后进行检验,并将配置的offer_ip及需要下载启动的文件名插入返回报文,广播回客户端,客户端接收后根据信息启动TFTP下载启动文件。传输过程中包含了重传策略,服务器接收检验及转发处理等(RFC951)。
此处包含一个鸡和蛋的问题,即如果客户端不知道自己IP地址,服务器怎么发送IP报文到客户端。
无论何时一条引导应答被发送,发送设备执行下列操作:
1.如果客户端知道自己的IP地址('ciaddr'字段非零),因为客户端能够回应ARPs (Address Resolution Protocol, 6.4.1.2),那么IP能够正常发送。
2.如果客户端还不知道自己的IP地址(ciaddr是零),客户端就不能回应引导应答发送程序回的ARPs。这时有两种选择:
a.如果发送程序有必需的核心或驱动钩子程序来人工建立ARP地址缓冲条目,就可以使用'chaddr'和'yiaddr'字段填入一个条目。当然,这个条目象正常ARP建立的其它条目一样有一个生命时间,引导应答的发送程序就能够简单地发送引导应答到客户端的IP地址了。UNIX (4.2BSD)有这种功能。
b.如果发送程序缺少这些核心钩子程序,就只能简单发送引导应答到相应接口的广播地址。这只是在前面情况外的额外的广播。
通信流程大致如下,
(0.0.0.0) Client --(<broadcast>, 67)--> Server
TFTP <---- Ip and file <--(<broadcast>, 68)-- (offer ip and boot file name)
Note: ARP(Address Resolution Protocol),是根据IP地址获取物理(mac)地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。地址解析协议是建立在网络中各个主机互相信任的基础上的,网络上的主机可以自主发送ARP应答消息,其他主机收到应答报文时不会检测该报文的真实性就会将其记入本机ARP缓存;由此攻击者就可以向某一主机发送伪ARP应答报文,使其发送的信息无法到达预期的主机或到达错误的主机,这就构成了一个ARP欺骗。ARP命令可用于查询本机ARP缓存中IP地址和MAC地址的对应关系、添加或删除静态对应关系等。相关协议有RARP、代理ARP。NDP用于在IPv6中代替地址解析协议。
4 数据报文格式 / Data Message Format
字段 字节数 位号 描述
------ --------- ------ ------
Op 1 1 Packet op code / Message type.包操作码/消息类型,
1 = BOOTREQUEST(引导请求), 2 = BOOTREPLY(引导应答)
Htype 1 2 Hardware address type, 硬件地址类型
'1' = 10mb ethernet 10M以太网
Hlen 1 3 Hardware address length,硬件地址长度
(eg '6' for 10mb ethernet). 例如'6'是10M以太网
Hops 1 4 client sets to zero, 客户端设置成0
optionally used by gateways,在跨越网关引导时网关可选择使用
in cross-gateway booting.
Xid 4 5-8 Transaction ID, a random number, used to match this boot request
with the responses it generates.
事务ID,一个随机数,用来匹配引用请求和应答
Secs 2 9-10 Seconds elapsed since client started trying to boot,filled in by client
由客户端填写,客户端引导开始后的过去的秒数
--(Flags) 2 11-12 unused未使用
Ciaddr 4 13-16 Client IP address,filled in by client in bootrequest if known.
客户端IP地址,如果客户端知道就在引导请求中填入
Yiaddr 4 17-20 'Your' (client) IP address,'你的'(客户端)IP地址
filled by server if client doesn't know its own address (ciaddr was 0)
如果客户端不知道它的地址(ciaddr是0),服务器填入
Siaddr 4 21-24 Server IP address,服务器IP地址
returned in bootreply by server,由服务器在引导应答返回
Giaddr 4 25-28 Gateway IP address,used in optional cross-gateway booting
网关IP地址,在跨越网关引导中可以选择使用
Chaddr 16 29-44 Client hardware address,客户端硬件地址
filled in by client.由客户端填写,前6位mac_id,后10位填充0
Sname 64 45-108 Optional server host name, null terminated string.
可选的服务器主机名,空结束的字符串
File 128 109-236 Boot file name, null terminated string;
引导文件名,空结束的字符串
'generic' name or null in bootrequest,
fully qualified directory-path name in bootreply
在引导请求中使用'通用'名称或空
是引导应答中使用确切的目录路径名称
Vend 64 237-300 Optional vendor-specific area,可选的卖主指定的区域,
e.g. could be hardware type/serial on request,
例如,可以是请求硬件类型/序列,
or 'capability' / remote file system handleon reply.
或应答的性能/远端文件系统句柄。
This info may be set aside for use by a third phase bootstrap or kernel.
这些信息留给第三方分析引导或核心(程序)使用。
5 报文加码实现
分别对服务端和客户端的加码利用 Python 进行实现,解码部分将在客户端和服务器的实现代码中完成,
其中使用到了 binascii 模块,wmi 模块,struct 模块。
import binascii
import socket
import struct
import wmi
import random
w = wmi.WMI() class ServerCodeC: @staticmethod
def offer(transaction_id, client_ip_offer, server_ip, client_mac_id, file_path):
SERVER_NAME = 'bootpserver'
VENDOR = ''
client_mac_id = binascii.unhexlify(client_mac_id.replace(':', ''))
transaction_id = binascii.unhexlify(transaction_id)
packet = b''
packet += b'\x02' # op
packet += b'\x01' # htype
packet += b'\x06' # hlen
packet += b'\x00' # hops
packet += transaction_id
packet += b'\x00\x00' # secs
packet += b'\x80\x00' # flags (broadcast)
packet += b'\x00\x00\x00\x00' # current client ip
packet += socket.inet_aton(client_ip_offer) # next current client ip offer
packet += socket.inet_aton(server_ip) # server ip
packet += b'\x00\x00\x00\x00' # gateway ip
packet += client_mac_id # Client mac id #TODO: Change it
packet += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # client mac id padding
packet += SERVER_NAME.encode('utf-8')
packet += b"\x00"*(64-len(SERVER_NAME))
packet += file_path.encode('utf-8')
packet += b"\x00"*(128-len(file_path))
packet += VENDOR.encode('utf-8')
packet += b"\x00"*(64-len(VENDOR))
return packet @staticmethod
def collect(msg):
msgBody = {}
m = list(struct.unpack('%dc' % len(msg), msg))
msgBody['op'] = m[0]
msgBody['htype'] = m[1]
msgBody['hlen'] = m[2]
msgBody['hops'] = m[3]
msgBody['xid'] = ''.join(['%02x' % ord(x) for x in m[4:8]]) # transaction_id
msgBody['secs'] = m[8:10]
msgBody['flags'] = m[10:12]
msgBody['ciaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[12:16]), msg[12:16]))).rstrip('.')
msgBody['yiaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[16:20]), msg[16:20]))).rstrip('.')
msgBody['siaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[20:24]), msg[20:24]))).rstrip('.')
msgBody['giaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[24:28]), msg[24:28]))).rstrip('.')
msgBody['chaddr'] = ''.join(['%02x:' % ord(x) for x in m[28:34]])[:-1] # Client_mac_id (Delete last one ':')
msgBody['sname'] = msg[44:108].decode('utf-8').strip('\x00')
msgBody['file'] = msg[108:236].decode('utf-8').strip('\x00')
msgBody['vend'] = msg[236:300]
return msgBody class ClientCodeC():
transaction_id = None
client_mac_id = None @classmethod
def get_xid_macid(cls):
xid = ''
for i in range(8):
xid += hex(random.randint(0, 15))[-1]
cls.transaction_id = xid mac_id = []
for network in w.Win32_NetworkAdapterConfiguration(IPEnabled=1):
mac_id.append(network.MACAddress)
cls.client_mac_id = mac_id[0].lower() @staticmethod
def request():
SERVER_NAME = ''
VENDER = ''
transaction_id = binascii.unhexlify(ClientCodeC.transaction_id)
client_mac_id = binascii.unhexlify(ClientCodeC.client_mac_id.replace(':', '')) packet = b''
packet += b'\x01' # request op 1 1
packet += b'\x01' # htype 2 1
packet += b'\x06' # hlen 3 1
packet += b'\x00' # hops 4 1
packet += transaction_id # transaction_id 5-8 4
packet += b'\x00\x00' # secs 9-10 2
# TODO: Add resend time count
packet += b'\x80\x00' # flags(broadcast) 11-12 2
packet += b'\x00\x00\x00\x00' # client ip 13-16 4
packet += b'\x00\x00\x00\x00' # your client ip 17-20 4
packet += b'\x00\x00\x00\x00' # server ip 21-24 4
packet += b'\x00\x00\x00\x00' # gateway ip 25-28 4
packet += client_mac_id # mac id 29-34 6
packet += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # mac id placeholder 35-44 10
packet += b'\x00' * 64 # server name 45-108 64
packet += b'\x00' * 128 # file name 109-236 128
packet += VENDER.encode('utf-8') # vender info 237-300
packet += b"\x00"*(64-len(VENDER))
return packet @staticmethod
def collect(msg):
msgBody = {}
m = list(struct.unpack('%dc' % len(msg), msg))
msgBody['op'] = m[0]
msgBody['htype'] = m[1]
msgBody['hlen'] = m[2]
msgBody['hops'] = m[3]
msgBody['xid'] = ''.join(['%02x' % ord(x) for x in m[4:8]]) # transaction_id
msgBody['secs'] = m[8:10]
msgBody['flags'] = m[10:12]
msgBody['ciaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[12:16]), msg[12:16]))).rstrip('.')
msgBody['yiaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[16:20]), msg[16:20]))).rstrip('.')
msgBody['siaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[20:24]), msg[20:24]))).rstrip('.')
msgBody['giaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[24:28]), msg[24:28]))).rstrip('.')
msgBody['chaddr'] = ''.join(['%02x:' % ord(x) for x in m[28:34]])[:-1] # Client_mac_id (Delete last one ':')
msgBody['sname'] = msg[44:108].decode('utf-8').strip('\x00')
msgBody['file'] = msg[108:236].decode('utf-8').strip('\x00')
msgBody['vend'] = msg[236:300]
return msgBody
相关阅读
1. binascii 模块
2. wmi 模块
3. struct 模块
4. DHCP
参考链接
http://www.360doc.com/content/07/0822/15/39230_688439.shtml
http://blog.csdn.net/jxh_123/article/details/26449715
http://baike.baidu.com/item/ARP/609343
Python的网络编程[3] -> BOOTP 协议[0] -> BOOTP 的基本理论的更多相关文章
- Python的网络编程[4] -> DHCP 协议[0] -> DHCP 的基本理论
DHCP协议 / DHCP Protocol 目录 DHCP 基本理论 DHCP 通信流程 DHCP 完整报文 DHCP 的 Optional 字段 DHCP 的报文类型 1 DHCP 基本理论 DH ...
- Python的网络编程[1] -> FTP 协议[0] -> FTP 的基本理论
FTP协议 / FTP Protocol FTP全称为File Transfer Protocol(文件传输协议),常用于Internet上控制文件的双向传输,常用的操作有上传和下载.基于TCP/IP ...
- Python的网络编程[2] -> TFTP 协议[0] -> TFTP 的基本理论
TFTP 的基本理论 目录 通信流程 数据报文格式 传输终结 异常处理 数据丢失和超时 TFTP(Trivial File Transfer Protocol,简单文件传输协议)是UDP协议族中的一个 ...
- Python的网络编程[6] -> Modbus 协议 -> Modbus 的基本理论与 Python 实现
Modbus协议 / Modbus Protocol 目录 Modbus 协议简介 Modbus RTU协议 Modbus TCP协议与 Python 实现 Modbus 功能码 Modbus TCP ...
- Python的网络编程[1] -> FTP 协议[2] -> 使用 ftplib 建立 FTP 客户端
使用 ftplib 建立 FTP 客户端 用于建立FTP Client,与 pyftplib 建立的 Server 进行通信. 快速导航 1. 模块信息 2. 建立 FTP 客户端 1. 模块信息 1 ...
- Python的网络编程[4] -> DHCP 协议[1] -> DHCP 的 Python 实现
DHCP实现 / DHCP Implement 目录 DHCP 服务器建立过程 DHCP 报文加码实现过程 下面介绍建立一个简单的DHCP服务器,主要用于对基本的DHCP请求进行响应,目前只提供一个I ...
- Python的网络编程[1] -> FTP 协议[1] -> 使用 pyftplib 建立 FTP 服务器
使用 pyftplib 建立 FTP 服务器 pyftplib 主要用于建立 FTP Server,与 ftplib 建立的 Client 进行通信. 快速导航 1. 模块信息 2. 建立 FTP 服 ...
- Python的网络编程[2] -> TFTP 协议[1] -> TFTP 的 Python 实现
TFTP实现 / TFTP Implement 目录 TFTP 的服务器建立过程 TFTP 的客户端建立过程 1 TFTP 的服务器建立过程 服务器建立步骤主要有: (1) 设定服务器IP和 ...
- python之网络编程
本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道.FIFO.消息队列) 同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 共享内存(匿名的和具名的) 远程过程调用 ...
随机推荐
- 如何在Apache中使用PHP处理PHP文件
一.将PHP预处理器作为Apache的模块(插件) Apache软件自身的功能都是基于模块化管理的. 将PHP预处理器作为Apache的一个模块即可. 在apache/conf/httpd.conf的 ...
- USACO Section1.1 Friday the Thirteenth 解题报告
friday解题报告 —— icedream61 博客园(转载请注明出处) -------------------------------------------------------------- ...
- Python学习-day18 Web框架
众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 ...
- ASP.Net MVC+EF架构
ASP.Net MVC是UI层的框架,EF是数据访问的逻辑. 如果在Controller中using DbContext,把查询的结果的对象放到cshtml中显示,那么一旦在cshtml中访问关联属性 ...
- ERC720和erc721的区别
有一阵子,Ethereum网络突然变的特别拥堵,原因是兴起了一款以太坊养猫的Dapp游戏,超级可爱的猫形象,再加上配种,繁殖和拍卖等丰富的玩法,风靡了币圈. 一时间币圈大大小小的人都在撸猫,以太坊网络 ...
- HDU 3577 Fast Arrangement ( 线段树 成段更新 区间最值 区间最大覆盖次数 )
线段树成段更新+区间最值. 注意某人的乘车区间是[a, b-1],因为他在b站就下车了. #include <cstdio> #include <cstring> #inclu ...
- HDU 1937 J - Justice League
J - Justice League Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u ...
- [洛谷P3807]【模板】卢卡斯定理
题目大意:给你$n,m,p(p \in \rm prime)$,求出$C_{n + m}^m\bmod p(可能p\leqslant n,m)$ 题解:卢卡斯$Lucas$定理,$C_B^A\bmod ...
- 洛谷 P3747 [六省联考2017]相逢是问候 解题报告
P3747 [六省联考2017]相逢是问候 题目描述 \(\text {Informatik verbindet dich und mich.}\) 信息将你我连结. \(B\) 君希望以维护一个长度 ...
- bzoj3561 莫比乌斯反演
DZY Loves Math VI Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 518 Solved: 344[Submit][Status][D ...