BOOTP协议 / BOOTP Protocol


目录

  1. 基本理论
  2. BOOTP 与 DHCP
  3. 通信流程
  4. 数据报文格式
  5. 报文加解码实现

1. 基本理论 / Basic Theory

BOOTP(Bootstrap Protocol)是一种引导协议,基于RFC951协议,基于UDP协议,也称为自举协议,是DHCP协议的前身。BOOTP用于无盘工作站(类似网吧无盘结构)的局域网中,可以让无盘工作站从一个中心服务器上获得IP地址。通过BOOTP协议可以为局域网中的无盘工作站分配动态IP地址,这样就不需要管理员去为每个用户去设置静态IP地址。

BOOTP使用UDP报文传输,并使用保留端口号67BOOTP服务器,客户端使用此端口作为目标端口发送请求,通常是广播)和68BOOTP客户端,服务器使用此端口作为目标端口发送应答)工作。使用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地址池中取一个地址分配给该计算机。

通信流程 / 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 的基本理论相关推荐

  1. Python的网络编程[1] - FTP 协议[1] - 使用 pyftplib 建立 FTP 服务器

    使用 pyftplib 建立 FTP 服务器 pyftplib 主要用于建立 FTP Server,与 ftplib 建立的 Client 进行通信. 快速导航 1. 模块信息 2. 建立 FTP 服 ...

  2. Python高级网络编程系列之第一篇

    在上一篇中我们简单的说了一下Python中网络编程的基础知识(相关API就不解释了),其中还有什么细节的知识点没有进行说明,如什么是TCP/IP协议有几种状态,什么是TCP三次握手,什么是TCP四次握 ...

  3. Python Socket网络编程(二)局域网内和局域网与广域网的持续通信

    目录 前言 IP地址 简介 公有IP 私有IP 局域网之间网络通信 前提 功能描述 源码 运行结果 局域网与广域网网络通信 前提 源码 结语 前言 本系列博客是笔者学习Python Socket的过程 ...

  4. Python Socket网络编程(一)初识Socket和Socket初步使用

    目录 前言 网络编程 实质 IP地址和端口 数据传输协议 协议 Socket 概念 套接字 socket对象方法 初步使用 功能 源码 运行结果 结语 前言 本系列博客是笔者学习Python Sock ...

  5. python recv_python网络编程调用recv函数完整接收数据的三种方法

    最近在使用python进行网络编程开发一个通用的tcpclient测试小工具.在使用socket进行网络编程中,如何判定对端发送一条报文是否接收完成,是进行socket网络开发必须要考虑的一个问题.这 ...

  6. 0x011.Python学习-网络编程、PortScan

    Python3 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口 ...

  7. 用 Python 写网络编程(四)

    本文首发于TesterHome社区,作者是资深游戏测试开发工程师陈子昂.用 Python 写网络编程共四篇,今天分享的是第四篇.原文链接:https://testerhome.com/topics/2 ...

  8. iOS网络编程开发—HTTP协议

    iOS网络编程开发-HTTP协议 说明:apache tomcat服务器必须占用8080端口 一.URL 1.基本介绍 URL的全称是Uniform Resource Locator(统一资源定位符) ...

  9. WinSock API网络编程——TCP/IP协议详解

     WinSock API网络编程--TCP/IP协议(http://www.impcas.ac.cn/usr/lujun/browse.asp?id=winsock_tcp)            ...

最新文章

  1. cached-query 将缓存和查询数据库高速连接起来的轻类库
  2. python中all是什么意思_Python中的__all__
  3. Chromebook开发者模式Linux,Chromebook 的开发者模式和开发者版本有什么区别?
  4. 计算机系统维护技术txt,计算机系统维护技术A卷
  5. 线性搜索或顺序搜索算法在Java中如何工作? 示例教程
  6. php画图抗锯齿,​CSS3如何实现字体抗锯齿渲染效果?-webkit-font-smoothing属性(实例)...
  7. 计算机考试可以用平板电脑吗,操作计算机等级考试平板电脑可以吗
  8. 清华大学出来的工资有多高?| 文末送书
  9. Win7下更改iTunes备份路径最便捷的方法
  10. [附源码]Python计算机毕业设计常见病辅助食疗系统
  11. Monte-Carlo Dropout(蒙特卡罗 dropout),Aleatoric Uncertainty,Epistemic Uncertainty
  12. 电压(电流)运算放大器为什么要增大(减小)输入阻抗?
  13. web文件上传-0x00漏洞
  14. 入门必看!ui设计分类有哪些?【萧蕊冰】
  15. C/C++中的exit()函数
  16. Object is possibly undefined
  17. python学习——构建前端
  18. 【Liunx】Navicat连接ubuntu下mysql
  19. 感觉到大腿内的肌肉出血,应该用绳子包扎肌肉上侧还是下侧?
  20. 海思芯片部署MPP并验证功能

热门文章

  1. 用Go语言开发以太坊合约
  2. kuangbin-poj题目归类
  3. 用4年多时间, 带领微软重登全球市值第一宝座, 纳德拉是如何做到的?
  4. mongoDB 定长集合(capped collection)
  5. Java实现 蓝桥杯 猜算式
  6. 《中国新歌声》第二季再掀暑期音乐热浪 爱奇艺7月14日全网独播
  7. Python一日一练07----冒泡排序
  8. jsplumb设置锚点_记录一次基于jsPlumb流程图编辑器的开发过程
  9. android灰色滤镜布局
  10. 自动生成html基本结构,如何创建网页html?