-
Notifications
You must be signed in to change notification settings - Fork 519
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add example how to send NOTIFY message (#1007)
- Loading branch information
Showing
1 changed file
with
83 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
#!/usr/bin/python | ||
""" | ||
Minimalistic RFC 1996-like NOTIFY sender. | ||
""" | ||
import argparse | ||
import ipaddress | ||
import socket | ||
|
||
import dns.flags | ||
import dns.inet | ||
import dns.message | ||
import dns.name | ||
import dns.opcode | ||
import dns.query | ||
import dns.rrset | ||
import dns.rdataclass | ||
import dns.rdatatype | ||
|
||
|
||
def main(): | ||
"""Also prints all inputs and intermediate values""" | ||
parser = argparse.ArgumentParser( | ||
description="Send DNS NOTIFY mesage via UDP, optionally with synthetized SOA RR " | ||
"in ANSWER section. No checks. It's not RFC 1996 sect 3.6 compliant sender." | ||
) | ||
parser.add_argument("--source", type=ipaddress.ip_address, help="source IP address") | ||
parser.add_argument("--port", type=int, help="target port", default=53) | ||
parser.add_argument("target", type=ipaddress.ip_address, help="target IP address") | ||
parser.add_argument("zone", type=dns.name.from_text) | ||
parser.add_argument( | ||
"serial", | ||
nargs="?", | ||
type=int, | ||
help="optional serial - adds SOA RR into ANSWER section", | ||
) | ||
parser.add_argument( | ||
"--rdclass", | ||
default=dns.rdataclass.IN, | ||
type=dns.rdataclass.from_text, | ||
help="DNS class, defaults to IN", | ||
) | ||
args = parser.parse_args() | ||
if args.source: | ||
if dns.inet.af_for_address(str(args.target)) != dns.inet.af_for_address( | ||
str(args.source) | ||
): | ||
parser.error("address family for source and target must be the same") | ||
|
||
print(args) | ||
msg = construct_msg(args) | ||
print(msg) | ||
udp_send(msg, args) | ||
|
||
|
||
def construct_msg(args): | ||
"""if args.serial is specified it creates fake SOA RR with given serial""" | ||
msg = dns.message.make_query( | ||
args.zone, dns.rdatatype.SOA, rdclass=args.rdclass, flags=dns.flags.AA | ||
) | ||
msg.set_opcode(dns.opcode.NOTIFY) | ||
if args.serial: | ||
soa = dns.rrset.from_text_list( | ||
name=args.zone, | ||
ttl=0, | ||
rdclass=args.rdclass, | ||
rdtype=dns.rdatatype.SOA, | ||
text_rdatas=[f". . {args.serial} 0 0 0 0"], | ||
) | ||
msg.answer.append(soa) | ||
return msg | ||
|
||
|
||
def udp_send(msg, args): | ||
"""ignores checks prescribed by RFC 1996 sect 3.6""" | ||
afam = dns.inet.af_for_address(str(args.target)) | ||
sock = socket.socket(afam, socket.SOCK_DGRAM) | ||
if args.source: | ||
sock.bind((str(args.source), 0)) | ||
dns.query.send_udp(sock, what=msg, destination=(str(args.target), args.port)) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |