Python的网络编程[3] - BOOTP 协议[0] - BOOTP 的基本理论
BOOTP协议 / BOOTP Protocol
目录
- 基本理论
- BOOTP 与 DHCP
- 通信流程
- 数据报文格式
- 报文加解码实现
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 模块。
1 import binascii 2 import socket 3 import struct 4 import wmi 5 import random 6 w = wmi.WMI() 7 8 class ServerCodeC: 9 10 @staticmethod 11 def offer(transaction_id, client_ip_offer, server_ip, client_mac_id, file_path): 12 SERVER_NAME = 'bootpserver' 13 VENDOR = '' 14 client_mac_id = binascii.unhexlify(client_mac_id.replace(':', '')) 15 transaction_id = binascii.unhexlify(transaction_id) 16 packet = b'' 17 packet += b'\x02' # op 18 packet += b'\x01' # htype 19 packet += b'\x06' # hlen 20 packet += b'\x00' # hops 21 packet += transaction_id 22 packet += b'\x00\x00' # secs 23 packet += b'\x80\x00' # flags (broadcast) 24 packet += b'\x00\x00\x00\x00' # current client ip 25 packet += socket.inet_aton(client_ip_offer) # next current client ip offer 26 packet += socket.inet_aton(server_ip) # server ip 27 packet += b'\x00\x00\x00\x00' # gateway ip 28 packet += client_mac_id # Client mac id #TODO: Change it 29 packet += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # client mac id padding 30 packet += SERVER_NAME.encode('utf-8') 31 packet += b"\x00"*(64-len(SERVER_NAME)) 32 packet += file_path.encode('utf-8') 33 packet += b"\x00"*(128-len(file_path)) 34 packet += VENDOR.encode('utf-8') 35 packet += b"\x00"*(64-len(VENDOR)) 36 return packet 37 38 @staticmethod 39 def collect(msg): 40 msgBody = {} 41 m = list(struct.unpack('%dc' % len(msg), msg)) 42 msgBody['op'] = m[0] 43 msgBody['htype'] = m[1] 44 msgBody['hlen'] = m[2] 45 msgBody['hops'] = m[3] 46 msgBody['xid'] = ''.join(['%02x' % ord(x) for x in m[4:8]]) # transaction_id 47 msgBody['secs'] = m[8:10] 48 msgBody['flags'] = m[10:12] 49 msgBody['ciaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[12:16]), msg[12:16]))).rstrip('.') 50 msgBody['yiaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[16:20]), msg[16:20]))).rstrip('.') 51 msgBody['siaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[20:24]), msg[20:24]))).rstrip('.') 52 msgBody['giaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[24:28]), msg[24:28]))).rstrip('.') 53 msgBody['chaddr'] = ''.join(['%02x:' % ord(x) for x in m[28:34]])[:-1] # Client_mac_id (Delete last one ':') 54 msgBody['sname'] = msg[44:108].decode('utf-8').strip('\x00') 55 msgBody['file'] = msg[108:236].decode('utf-8').strip('\x00') 56 msgBody['vend'] = msg[236:300] 57 return msgBody 58 59 class ClientCodeC(): 60 transaction_id = None 61 client_mac_id = None 62 63 @classmethod 64 def get_xid_macid(cls): 65 xid = '' 66 for i in range(8): 67 xid += hex(random.randint(0, 15))[-1] 68 cls.transaction_id = xid 69 70 mac_id = [] 71 for network in w.Win32_NetworkAdapterConfiguration(IPEnabled=1): 72 mac_id.append(network.MACAddress) 73 cls.client_mac_id = mac_id[0].lower() 74 75 @staticmethod 76 def request(): 77 SERVER_NAME = '' 78 VENDER = '' 79 transaction_id = binascii.unhexlify(ClientCodeC.transaction_id) 80 client_mac_id = binascii.unhexlify(ClientCodeC.client_mac_id.replace(':', '')) 81 82 packet = b'' 83 packet += b'\x01' # request op 1 1 84 packet += b'\x01' # htype 2 1 85 packet += b'\x06' # hlen 3 1 86 packet += b'\x00' # hops 4 1 87 packet += transaction_id # transaction_id 5-8 4 88 packet += b'\x00\x00' # secs 9-10 2 89 # TODO: Add resend time count 90 packet += b'\x80\x00' # flags(broadcast) 11-12 2 91 packet += b'\x00\x00\x00\x00' # client ip 13-16 4 92 packet += b'\x00\x00\x00\x00' # your client ip 17-20 4 93 packet += b'\x00\x00\x00\x00' # server ip 21-24 4 94 packet += b'\x00\x00\x00\x00' # gateway ip 25-28 4 95 packet += client_mac_id # mac id 29-34 6 96 packet += b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # mac id placeholder 35-44 10 97 packet += b'\x00' * 64 # server name 45-108 64 98 packet += b'\x00' * 128 # file name 109-236 128 99 packet += VENDER.encode('utf-8') # vender info 237-300 100 packet += b"\x00"*(64-len(VENDER)) 101 return packet 102 103 @staticmethod 104 def collect(msg): 105 msgBody = {} 106 m = list(struct.unpack('%dc' % len(msg), msg)) 107 msgBody['op'] = m[0] 108 msgBody['htype'] = m[1] 109 msgBody['hlen'] = m[2] 110 msgBody['hops'] = m[3] 111 msgBody['xid'] = ''.join(['%02x' % ord(x) for x in m[4:8]]) # transaction_id 112 msgBody['secs'] = m[8:10] 113 msgBody['flags'] = m[10:12] 114 msgBody['ciaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[12:16]), msg[12:16]))).rstrip('.') 115 msgBody['yiaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[16:20]), msg[16:20]))).rstrip('.') 116 msgBody['siaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[20:24]), msg[20:24]))).rstrip('.') 117 msgBody['giaddr'] = ''.join(str(ord(i)) + '.' for i in list(struct.unpack('%dc' % len(msg[24:28]), msg[24:28]))).rstrip('.') 118 msgBody['chaddr'] = ''.join(['%02x:' % ord(x) for x in m[28:34]])[:-1] # Client_mac_id (Delete last one ':') 119 msgBody['sname'] = msg[44:108].decode('utf-8').strip('\x00') 120 msgBody['file'] = msg[108:236].decode('utf-8').strip('\x00') 121 msgBody['vend'] = msg[236:300] 122 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
转载于:https://www.cnblogs.com/stacklike/p/8149681.html
Python的网络编程[3] - BOOTP 协议[0] - BOOTP 的基本理论相关推荐
- Python的网络编程[1] - FTP 协议[1] - 使用 pyftplib 建立 FTP 服务器
使用 pyftplib 建立 FTP 服务器 pyftplib 主要用于建立 FTP Server,与 ftplib 建立的 Client 进行通信. 快速导航 1. 模块信息 2. 建立 FTP 服 ...
- Python高级网络编程系列之第一篇
在上一篇中我们简单的说了一下Python中网络编程的基础知识(相关API就不解释了),其中还有什么细节的知识点没有进行说明,如什么是TCP/IP协议有几种状态,什么是TCP三次握手,什么是TCP四次握 ...
- Python Socket网络编程(二)局域网内和局域网与广域网的持续通信
目录 前言 IP地址 简介 公有IP 私有IP 局域网之间网络通信 前提 功能描述 源码 运行结果 局域网与广域网网络通信 前提 源码 结语 前言 本系列博客是笔者学习Python Socket的过程 ...
- Python Socket网络编程(一)初识Socket和Socket初步使用
目录 前言 网络编程 实质 IP地址和端口 数据传输协议 协议 Socket 概念 套接字 socket对象方法 初步使用 功能 源码 运行结果 结语 前言 本系列博客是笔者学习Python Sock ...
- python recv_python网络编程调用recv函数完整接收数据的三种方法
最近在使用python进行网络编程开发一个通用的tcpclient测试小工具.在使用socket进行网络编程中,如何判定对端发送一条报文是否接收完成,是进行socket网络开发必须要考虑的一个问题.这 ...
- 0x011.Python学习-网络编程、PortScan
Python3 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口 ...
- 用 Python 写网络编程(四)
本文首发于TesterHome社区,作者是资深游戏测试开发工程师陈子昂.用 Python 写网络编程共四篇,今天分享的是第四篇.原文链接:https://testerhome.com/topics/2 ...
- iOS网络编程开发—HTTP协议
iOS网络编程开发-HTTP协议 说明:apache tomcat服务器必须占用8080端口 一.URL 1.基本介绍 URL的全称是Uniform Resource Locator(统一资源定位符) ...
- WinSock API网络编程——TCP/IP协议详解
WinSock API网络编程--TCP/IP协议(http://www.impcas.ac.cn/usr/lujun/browse.asp?id=winsock_tcp) ...
最新文章
- cached-query 将缓存和查询数据库高速连接起来的轻类库
- python中all是什么意思_Python中的__all__
- Chromebook开发者模式Linux,Chromebook 的开发者模式和开发者版本有什么区别?
- 计算机系统维护技术txt,计算机系统维护技术A卷
- 线性搜索或顺序搜索算法在Java中如何工作? 示例教程
- php画图抗锯齿,​CSS3如何实现字体抗锯齿渲染效果?-webkit-font-smoothing属性(实例)...
- 计算机考试可以用平板电脑吗,操作计算机等级考试平板电脑可以吗
- 清华大学出来的工资有多高?| 文末送书
- Win7下更改iTunes备份路径最便捷的方法
- [附源码]Python计算机毕业设计常见病辅助食疗系统
- Monte-Carlo Dropout(蒙特卡罗 dropout),Aleatoric Uncertainty,Epistemic Uncertainty
- 电压(电流)运算放大器为什么要增大(减小)输入阻抗?
- web文件上传-0x00漏洞
- 入门必看!ui设计分类有哪些?【萧蕊冰】
- C/C++中的exit()函数
- Object is possibly undefined
- python学习——构建前端
- 【Liunx】Navicat连接ubuntu下mysql
- 感觉到大腿内的肌肉出血,应该用绳子包扎肌肉上侧还是下侧?
- 海思芯片部署MPP并验证功能