在Python中实现DNS消息名称压缩算法

在Python中实现DNS消息名称压缩算法,python,regex,search,dns,Python,Regex,Search,Dns,在DNS消息中,域名表示如下: Address Value ---------------------------------------------------------------- 0x00C 0x5 s t o r e 0x7 e x a m p l e 0x3 c o m 0x0 0x023 0x4 b l o g 0xC012 在地址0x00C我们有store.example.com,在地址0x023我们有blog.example.com0xC012表

在DNS消息中,域名表示如下:

Address    Value
----------------------------------------------------------------
0x00C      0x5 s t o r e 0x7 e x a m p l e 0x3 c o m 0x0
0x023      0x4 b l o g  0xC012
在地址
0x00C
我们有
store.example.com
,在地址
0x023
我们有
blog.example.com
0xC012
表示指向
0x012
的指针,其中
example.com
从第一个域名开始,因此我们不必重复它

我使用以下代码成功地将域名转换为标签数组:

labels = []
for part in self.domain.split('.'):
    label = part.encode('ascii')
    length = len(label).to_bytes(1, 'big')
    labels.append(length + label)
这为我提供了以下数组:

[b'\x04blog', b'\x07example', b'\x03com']
但是我很难构建一个正则表达式或一个高效函数来搜索已经为
\x04blog\x07example\x03com\x00
\x07example\x03com\x00
编写的消息部分。我想找到最长的比赛。我试着构建一个这样的正则表达式:

(((\x04blog)?\x07example)?\x03com)?\x00
但在这种情况下,正则表达式引擎似乎更喜欢只匹配
\x00
。我该如何解决这个问题


还有另一个问题:我们可以从技术上添加
my.blog.example.com
,它需要包含
0x2 m y 0xC023
,并且
0xC023
指向
blog.example.com

首先,对于我给你的错误提示,有更简单的事情要做。事实上,这里有比使用正则表达式简单得多的事情要做。正则表达式太强大了,无法做到这一点,您可以在不使用正则表达式的情况下实现相同的结果

DNS消息格式在中定义

第4.1.4节解释了名称压缩。 还请注意,您必须考虑不区分大小写的方面,如第2.3.3节所述

在下面的代码中应该是这样的情况,可以肯定 使用取自RFC的示例名称进行优化:

#/usr/bin/python3
名称=['F.ISI.ARPA','FOO.F.ISI.ARPA','ARPA']
缓存={}
pos=0
结果=[]
对于名称中的名称:
labels=name.split('.'))
而len(标签):
键=“.”。联接(标签)
如果缓存中有key.lower():
results.append((缓存[key.lower()]+2**15+2**14).to_字节(2,'big'))
pos+=2
打破
其他:
label=labels.pop(0).encode('ascii')
长度=len(标签)。到_字节(1,‘大’)
结果.追加(长度+标签)
缓存[key.lower()]=pos
位置+=透镜(标签)+1
其他:
results.append(b'0')
pos+=1
打印(结果)
产生:

[b'\x01F', b'\x03ISI', b'\x04ARPA', b'0', b'\x03FOO', b'\xc0\x00', b'\xc0\x06']
[b'\x05store', b'\x07example', b'\x03com', b'0', b'\x04blog', b'\xc0\x06', b'\x02my', b'\xc0\x13']
如果改为使用您的示例:

names=['store.example.com', 'blog.example.com', 'my.blog.example.com']
它产生:

[b'\x01F', b'\x03ISI', b'\x04ARPA', b'0', b'\x03FOO', b'\xc0\x00', b'\xc0\x06']
[b'\x05store', b'\x07example', b'\x03com', b'0', b'\x04blog', b'\xc0\x06', b'\x02my', b'\xc0\x13']

如果不是很明显,是的,我编程这纯粹是作为一种学习经验。提示:如果你从右到左解析东西,并将全名存储为键,将编码值存储为值,那么问题就会少一些。从
com
开始,将其编码为
0x3 c o m 0x0
并保持
cache['com']=position
,然后转到
example
,对其进行编码并将
example.com
放入
缓存中,并在适当的位置进行压缩,在进行任何编码之前,请测试该值是否已存在于
缓存中。这是一种不用正则表达式的方法。你也可以看看在当前的DNS库中是如何实现的,给你一些想法……我意识到我写的指针是一个字节而不是两个字节。我试着把它们修好,希望我没有弄错。我还写了超过三个十六进制数字的地址,考虑到一条消息可能会占用512字节(0x200)。是的,我在问了这个问题后不久得出结论,我可能需要一个缓存。哦,我明白了,你从左到右写名字,逐步地把它的条目添加到缓存中,一旦剩下一个在缓存中的余数,你就放一个指针。偏离航线!对于将来阅读本文的任何人来说,名称中的指针由两个1位组成,后跟消息顶部的偏移量(剩余的两个字节)。域可以写在消息的不同部分,域名之间总是有更多的数据。因此,从0开始并以那样的方式递增
pos
并不是一件容易的事,但这段代码让人明白了一般的想法。@JacqueGoupil是的,职位会有“间隙”,这取决于你所处的位置,但这实际上取决于你所传达的信息;您只需要有一个通用函数,其中传递名称和当前位置,它将根据缓存的当前内容在给定位置对名称进行编码并递增。实际上,我使用了
(0xC000+len(message))。到_字节(2,'大')
在执行
message.append(长度+标签)
之前,在缓存中创建并存储指针。