if request_payload is None:
request_payload = payload
self.request_payload = request_payload
+ if pad < 0:
+ raise ValueError("pad must be non-negative")
self.pad = pad
@property
our_payload: int = 8192,
fudge: int = 300,
tsig_error: int = 0,
+ pad: Optional[int] = None,
) -> Message:
"""Make a message which is a response for the specified query.
- The message returned is really a response skeleton; it has all
- of the infrastructure required of a response, but none of the
- content.
+ The message returned is really a response skeleton; it has all of the infrastructure
+ required of a response, but none of the content.
- The response's question section is a shallow copy of the query's
- question section, so the query's question RRsets should not be
- changed.
+ The response's question section is a shallow copy of the query's question section,
+ so the query's question RRsets should not be changed.
*query*, a ``dns.message.Message``, the query to respond to.
*recursion_available*, a ``bool``, should RA be set in the response?
- *our_payload*, an ``int``, the payload size to advertise in EDNS
- responses.
+ *our_payload*, an ``int``, the payload size to advertise in EDNS responses.
*fudge*, an ``int``, the TSIG time fudge.
*tsig_error*, an ``int``, the TSIG error.
- Returns a ``dns.message.Message`` object whose specific class is
- appropriate for the query. For example, if query is a
- ``dns.update.UpdateMessage``, response will be too.
+ *pad*, a non-negative ``int`` or ``None``. If 0, the default, do not pad; otherwise
+ if not ``None`` add padding bytes to make the message size a multiple of *pad*.
+ Note that if padding is non-zero, an EDNS PADDING option will always be added to the
+ message. If ``None``, add padding following RFC 8467, namely if the request is
+ padded, pad the response to 468 otherwise do not pad.
+
+ Returns a ``dns.message.Message`` object whose specific class is appropriate for the
+ query. For example, if query is a ``dns.update.UpdateMessage``, response will be
+ too.
"""
if query.flags & dns.flags.QR:
response.set_opcode(query.opcode())
response.question = list(query.question)
if query.edns >= 0:
- response.use_edns(0, 0, our_payload, query.payload)
+ if pad is None:
+ # Set response padding per RFC 8467
+ pad = 0
+ for option in query.options:
+ if option.otype == dns.edns.OptionType.PADDING:
+ pad = 468
+ response.use_edns(0, 0, our_payload, query.payload, pad=pad)
if query.had_tsig:
response.use_tsig(
query.keyring,
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-import unittest
import binascii
+import unittest
-import dns.exception
import dns.edns
+import dns.exception
import dns.flags
import dns.message
import dns.name
import dns.rdataclass
import dns.rdatatype
-import dns.rrset
-import dns.tsig
-import dns.update
import dns.rdtypes.ANY.OPT
import dns.rdtypes.ANY.TSIG
+import dns.rrset
+import dns.tsig
import dns.tsigkeyring
-
+import dns.update
from tests.util import here
query_text = """id 1234
self.assertIsNotNone(q2.tsig)
self.assertEqual(q, q2)
+ def test_response_padding(self):
+ q = dns.message.make_query("www.example", "a", use_edns=0, pad=128)
+ w = q.to_wire()
+ self.assertEqual(len(w), 128)
+ # We need to go read the wire as the padding isn't instantiated in q.
+ pq = dns.message.from_wire(w)
+ r = dns.message.make_response(pq)
+ assert r.pad == 468
+ r = dns.message.make_response(pq, pad=0)
+ assert r.pad == 0
+ r = dns.message.make_response(pq, pad=40)
+ assert r.pad == 40
+ q = dns.message.make_query("www.example", "a", use_edns=0, pad=0)
+ w = q.to_wire()
+ pq = dns.message.from_wire(w)
+ r = dns.message.make_response(pq)
+ assert r.pad == 0
+
def test_prefer_truncation_answer(self):
q = dns.message.make_query("www.example", "a")
rrs = [