1 | # Copyright (C) 2009 Nominum, Inc.
|
---|
2 | #
|
---|
3 | # Permission to use, copy, modify, and distribute this software and its
|
---|
4 | # documentation for any purpose with or without fee is hereby granted,
|
---|
5 | # provided that the above copyright notice and this permission notice
|
---|
6 | # appear in all copies.
|
---|
7 | #
|
---|
8 | # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
|
---|
9 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
---|
10 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
|
---|
11 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
---|
12 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
---|
13 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
---|
14 | # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
---|
15 |
|
---|
16 | """EDNS Options"""
|
---|
17 |
|
---|
18 | NSID = 3
|
---|
19 |
|
---|
20 | class Option(object):
|
---|
21 | """Base class for all EDNS option types.
|
---|
22 | """
|
---|
23 |
|
---|
24 | def __init__(self, otype):
|
---|
25 | """Initialize an option.
|
---|
26 | @param rdtype: The rdata type
|
---|
27 | @type rdtype: int
|
---|
28 | """
|
---|
29 | self.otype = otype
|
---|
30 |
|
---|
31 | def to_wire(self, file):
|
---|
32 | """Convert an option to wire format.
|
---|
33 | """
|
---|
34 | raise NotImplementedError
|
---|
35 |
|
---|
36 | def from_wire(cls, otype, wire, current, olen):
|
---|
37 | """Build an EDNS option object from wire format
|
---|
38 |
|
---|
39 | @param otype: The option type
|
---|
40 | @type otype: int
|
---|
41 | @param wire: The wire-format message
|
---|
42 | @type wire: string
|
---|
43 | @param current: The offet in wire of the beginning of the rdata.
|
---|
44 | @type current: int
|
---|
45 | @param olen: The length of the wire-format option data
|
---|
46 | @type olen: int
|
---|
47 | @rtype: dns.ends.Option instance"""
|
---|
48 | raise NotImplementedError
|
---|
49 |
|
---|
50 | from_wire = classmethod(from_wire)
|
---|
51 |
|
---|
52 | def _cmp(self, other):
|
---|
53 | """Compare an ENDS option with another option of the same type.
|
---|
54 | Return < 0 if self < other, 0 if self == other, and > 0 if self > other.
|
---|
55 | """
|
---|
56 | raise NotImplementedError
|
---|
57 |
|
---|
58 | def __eq__(self, other):
|
---|
59 | if not isinstance(other, Option):
|
---|
60 | return False
|
---|
61 | if self.otype != other.otype:
|
---|
62 | return False
|
---|
63 | return self._cmp(other) == 0
|
---|
64 |
|
---|
65 | def __ne__(self, other):
|
---|
66 | if not isinstance(other, Option):
|
---|
67 | return False
|
---|
68 | if self.otype != other.otype:
|
---|
69 | return False
|
---|
70 | return self._cmp(other) != 0
|
---|
71 |
|
---|
72 | def __lt__(self, other):
|
---|
73 | if not isinstance(other, Option) or \
|
---|
74 | self.otype != other.otype:
|
---|
75 | return NotImplemented
|
---|
76 | return self._cmp(other) < 0
|
---|
77 |
|
---|
78 | def __le__(self, other):
|
---|
79 | if not isinstance(other, Option) or \
|
---|
80 | self.otype != other.otype:
|
---|
81 | return NotImplemented
|
---|
82 | return self._cmp(other) <= 0
|
---|
83 |
|
---|
84 | def __ge__(self, other):
|
---|
85 | if not isinstance(other, Option) or \
|
---|
86 | self.otype != other.otype:
|
---|
87 | return NotImplemented
|
---|
88 | return self._cmp(other) >= 0
|
---|
89 |
|
---|
90 | def __gt__(self, other):
|
---|
91 | if not isinstance(other, Option) or \
|
---|
92 | self.otype != other.otype:
|
---|
93 | return NotImplemented
|
---|
94 | return self._cmp(other) > 0
|
---|
95 |
|
---|
96 |
|
---|
97 | class GenericOption(Option):
|
---|
98 | """Generate Rdata Class
|
---|
99 |
|
---|
100 | This class is used for EDNS option types for which we have no better
|
---|
101 | implementation.
|
---|
102 | """
|
---|
103 |
|
---|
104 | def __init__(self, otype, data):
|
---|
105 | super(GenericOption, self).__init__(otype)
|
---|
106 | self.data = data
|
---|
107 |
|
---|
108 | def to_wire(self, file):
|
---|
109 | file.write(self.data)
|
---|
110 |
|
---|
111 | def from_wire(cls, otype, wire, current, olen):
|
---|
112 | return cls(otype, wire[current : current + olen])
|
---|
113 |
|
---|
114 | from_wire = classmethod(from_wire)
|
---|
115 |
|
---|
116 | def _cmp(self, other):
|
---|
117 | return cmp(self.data, other.data)
|
---|
118 |
|
---|
119 | _type_to_class = {
|
---|
120 | }
|
---|
121 |
|
---|
122 | def get_option_class(otype):
|
---|
123 | cls = _type_to_class.get(otype)
|
---|
124 | if cls is None:
|
---|
125 | cls = GenericOption
|
---|
126 | return cls
|
---|
127 |
|
---|
128 | def option_from_wire(otype, wire, current, olen):
|
---|
129 | """Build an EDNS option object from wire format
|
---|
130 |
|
---|
131 | @param otype: The option type
|
---|
132 | @type otype: int
|
---|
133 | @param wire: The wire-format message
|
---|
134 | @type wire: string
|
---|
135 | @param current: The offet in wire of the beginning of the rdata.
|
---|
136 | @type current: int
|
---|
137 | @param olen: The length of the wire-format option data
|
---|
138 | @type olen: int
|
---|
139 | @rtype: dns.ends.Option instance"""
|
---|
140 |
|
---|
141 | cls = get_option_class(otype)
|
---|
142 | return cls.from_wire(otype, wire, current, olen)
|
---|