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 18NSID = 3 19 20class 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 97class 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 122def get_option_class(otype): 123 cls = _type_to_class.get(otype) 124 if cls is None: 125 cls = GenericOption 126 return cls 127 128def 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) 143