Blame
Date:
Fri Dec 17 13:35:57 2021 UTC
Message:
Imported sources
001
2021-12-17
jrmu
#!/usr/bin/perl
002
2021-12-17
jrmu
003
2021-12-17
jrmu
package DNS;
004
2021-12-17
jrmu
005
2021-12-17
jrmu
use strict;
006
2021-12-17
jrmu
use warnings;
007
2021-12-17
jrmu
use OpenBSD::Pledge;
008
2021-12-17
jrmu
use OpenBSD::Unveil;
009
2021-12-17
jrmu
use Data::Dumper;
010
2021-12-17
jrmu
use File::Copy qw(copy);
011
2021-12-17
jrmu
012
2021-12-17
jrmu
my %conf = %main::conf;
013
2021-12-17
jrmu
my $chans = $conf{chans};
014
2021-12-17
jrmu
my $staff = $conf{staff};
015
2021-12-17
jrmu
my $key = $conf{key};
016
2021-12-17
jrmu
my $hash = $conf{hash};
017
2021-12-17
jrmu
my $hostname = $conf{hostname};
018
2021-12-17
jrmu
my $verbose = $conf{verbose};
019
2021-12-17
jrmu
my $ip4 = $conf{ip4};
020
2021-12-17
jrmu
my $ip6 = $conf{ip6};
021
2021-12-17
jrmu
my $ip6subnet = $conf{ip6subnet};
022
2021-12-17
jrmu
my $zonedir = $conf{zonedir};
023
2021-12-17
jrmu
my $hostnameif = $conf{hostnameif};
024
2021-12-17
jrmu
if (host($hostname) =~ /(\d+\.){3,}\d+/) {
025
2021-12-17
jrmu
$ip4 = $&;
026
2021-12-17
jrmu
}
027
2021-12-17
jrmu
main::cbind("msg", "-", "setrdns", \&msetrdns);
028
2021-12-17
jrmu
main::cbind("msg", "-", "delrdns", \&mdelrdns);
029
2021-12-17
jrmu
main::cbind("msg", "-", "setdns", \&msetdns);
030
2021-12-17
jrmu
main::cbind("msg", "-", "deldns", \&mdeldns);
031
2021-12-17
jrmu
main::cbind("msg", "-", "host", \&mhost);
032
2021-12-17
jrmu
main::cbind("msg", "-", "nextdns", \&mnextdns);
033
2021-12-17
jrmu
main::cbind("msg", "-", "readip6s", \&mreadip6s);
034
2021-12-17
jrmu
035
2021-12-17
jrmu
sub init {
036
2021-12-17
jrmu
unveil("$zonedir", "rwc") or die "Unable to unveil $!";
037
2021-12-17
jrmu
unveil("/usr/bin/doas", "rx") or die "Unable to unveil $!";
038
2021-12-17
jrmu
unveil("/usr/bin/host", "rx") or die "Unable to unveil $!";
039
2021-12-17
jrmu
unveil("$hostnameif", "rwc") or die "Unable to unveil $!";
040
2021-12-17
jrmu
}
041
2021-12-17
jrmu
042
2021-12-17
jrmu
# !setrdns 2001:bd8:: username.example.com
043
2021-12-17
jrmu
sub msetrdns {
044
2021-12-17
jrmu
my ($bot, $nick, $host, $hand, $text) = @_;
045
2021-12-17
jrmu
if (! (main::isstaff($bot, $nick))) { return; }
046
2021-12-17
jrmu
if ($text =~ /^([0-9A-Fa-f:\.]{3,})\s+([-0-9A-Za-z\.]+)$/) {
047
2021-12-17
jrmu
my ($ip, $hostname) = ($1, $2);
048
2021-12-17
jrmu
if (setrdns($ip, $ip6subnet, $hostname)) {
049
2021-12-17
jrmu
main::putserv($bot, "PRIVMSG $nick :$hostname set to $ip");
050
2021-12-17
jrmu
} else {
051
2021-12-17
jrmu
main::putserv($bot, "PRIVMSG $nick :ERROR: failed to set rDNS");
052
2021-12-17
jrmu
}
053
2021-12-17
jrmu
}
054
2021-12-17
jrmu
}
055
2021-12-17
jrmu
056
2021-12-17
jrmu
# !delrdns 2001:bd8::
057
2021-12-17
jrmu
sub mdelrdns {
058
2021-12-17
jrmu
my ($bot, $nick, $host, $hand, $text) = @_;
059
2021-12-17
jrmu
if (! (main::isstaff($bot, $nick))) { return; }
060
2021-12-17
jrmu
if ($text =~ /^([0-9A-Fa-f:\.]{3,})$/) {
061
2021-12-17
jrmu
my ($ip) = ($1);
062
2021-12-17
jrmu
if (delrdns($ip, $ip6subnet)) {
063
2021-12-17
jrmu
main::putserv($bot, "PRIVMSG $nick :$ip rDNS deleted");
064
2021-12-17
jrmu
} else {
065
2021-12-17
jrmu
main::putserv($bot, "PRIVMSG $nick :ERROR: failed to set rDNS");
066
2021-12-17
jrmu
}
067
2021-12-17
jrmu
}
068
2021-12-17
jrmu
}
069
2021-12-17
jrmu
# !setdns username 1.2.3.4
070
2021-12-17
jrmu
sub msetdns {
071
2021-12-17
jrmu
my ($bot, $nick, $host, $hand, $text) = @_;
072
2021-12-17
jrmu
if (! (main::isstaff($bot, $nick))) { return; }
073
2021-12-17
jrmu
if ($text =~ /^([-0-9A-Za-z\.]+)\s+([0-9A-Fa-f:\.]+)/) {
074
2021-12-17
jrmu
my ($name, $value) = ($1, $2);
075
2021-12-17
jrmu
if ($value =~ /:/ and setdns($name, $hostname, "AAAA", $value)) {
076
2021-12-17
jrmu
main::putserv($bot, "PRIVMSG $nick :$name.$hostname AAAA set to $value");
077
2021-12-17
jrmu
} elsif (setdns($name, $hostname, "A", $value)) {
078
2021-12-17
jrmu
main::putserv($bot, "PRIVMSG $nick :$name.$hostname A set to $value");
079
2021-12-17
jrmu
} else {
080
2021-12-17
jrmu
main::putserv($bot, "PRIVMSG $nick :ERROR: failed to set DNS");
081
2021-12-17
jrmu
}
082
2021-12-17
jrmu
}
083
2021-12-17
jrmu
}
084
2021-12-17
jrmu
085
2021-12-17
jrmu
# !deldns username
086
2021-12-17
jrmu
sub mdeldns {
087
2021-12-17
jrmu
my ($bot, $nick, $host, $hand, $text) = @_;
088
2021-12-17
jrmu
if (! (main::isstaff($bot, $nick))) { return; }
089
2021-12-17
jrmu
if ($text =~ /^([-0-9A-Za-z\.]+)$/) {
090
2021-12-17
jrmu
my ($name) = ($1);
091
2021-12-17
jrmu
if (setdns($name, $hostname)) {
092
2021-12-17
jrmu
main::putserv($bot, "PRIVMSG $nick :$text deleted");
093
2021-12-17
jrmu
} else {
094
2021-12-17
jrmu
main::putserv($bot, "PRIVMSG $nick :ERROR: failed to delete DNS records");
095
2021-12-17
jrmu
}
096
2021-12-17
jrmu
}
097
2021-12-17
jrmu
}
098
2021-12-17
jrmu
099
2021-12-17
jrmu
# !host username
100
2021-12-17
jrmu
sub mhost {
101
2021-12-17
jrmu
my ($bot, $nick, $host, $hand, $text) = @_;
102
2021-12-17
jrmu
if (! (main::isstaff($bot, $nick))) { return; }
103
2021-12-17
jrmu
if ($text =~ /^([-0-9A-Za-z:\.]{3,})/) {
104
2021-12-17
jrmu
my ($hostname) = ($1);
105
2021-12-17
jrmu
main::putserv($bot, "PRIVMSG $nick :".host($hostname));
106
2021-12-17
jrmu
}
107
2021-12-17
jrmu
}
108
2021-12-17
jrmu
109
2021-12-17
jrmu
# !nextdns username
110
2021-12-17
jrmu
sub mnextdns {
111
2021-12-17
jrmu
my ($bot, $nick, $host, $hand, $text) = @_;
112
2021-12-17
jrmu
if (! (main::isstaff($bot, $nick))) { return; }
113
2021-12-17
jrmu
if ($text =~ /^([-0-9a-zA-Z]+)/) {
114
2021-12-17
jrmu
main::putserv($bot, "PRIVMSG $nick :$text set to ".nextdns($text));
115
2021-12-17
jrmu
}
116
2021-12-17
jrmu
}
117
2021-12-17
jrmu
118
2021-12-17
jrmu
# !readip6s
119
2021-12-17
jrmu
sub mreadip6s {
120
2021-12-17
jrmu
my ($bot, $nick, $host, $hand, $text) = @_;
121
2021-12-17
jrmu
if (! (main::isstaff($bot, $nick))) { return; }
122
2021-12-17
jrmu
foreach my $line (readip6s($hostnameif)) {
123
2021-12-17
jrmu
print "$line\n"
124
2021-12-17
jrmu
}
125
2021-12-17
jrmu
}
126
2021-12-17
jrmu
127
2021-12-17
jrmu
# Return list of ipv6 addresses from filename
128
2021-12-17
jrmu
sub readip6s {
129
2021-12-17
jrmu
my ($filename) = @_;
130
2021-12-17
jrmu
my @lines = main::readarray($filename);
131
2021-12-17
jrmu
my @ipv6s;
132
2021-12-17
jrmu
foreach my $line (@lines) {
133
2021-12-17
jrmu
if ($line =~ /^\s*inet6\s+(alias\s+)?([0-9a-f:]{4,})\s+[0-9]+\s*$/i) {
134
2021-12-17
jrmu
push(@ipv6s, $2);
135
2021-12-17
jrmu
} elsif ($line =~ /^\s*([0-9a-f:]{4,})\s*$/i) {
136
2021-12-17
jrmu
push(@ipv6s, $1);
137
2021-12-17
jrmu
}
138
2021-12-17
jrmu
}
139
2021-12-17
jrmu
return @ipv6s;
140
2021-12-17
jrmu
}
141
2021-12-17
jrmu
142
2021-12-17
jrmu
# set rdns of $ip6 to $hostname given $subnet
143
2021-12-17
jrmu
# return true on success; false on failure
144
2021-12-17
jrmu
sub setrdns {
145
2021-12-17
jrmu
my ($ip6, $subnet, $hostname) = @_;
146
2021-12-17
jrmu
my $digits = ip6full($ip6);
147
2021-12-17
jrmu
$digits =~ tr/://d;
148
2021-12-17
jrmu
my $reversed = reverse($digits);
149
2021-12-17
jrmu
my $origin = substr($reversed, 32-$subnet/4);
150
2021-12-17
jrmu
$origin = join('.', split(//, $origin)).".ip6.arpa";
151
2021-12-17
jrmu
my $name = substr($reversed, 0, 32-$subnet/4);
152
2021-12-17
jrmu
$name = join('.', split(//, $name));
153
2021-12-17
jrmu
# delete old PTR records, then set new one
154
2021-12-17
jrmu
return setdns($name, $origin) && setdns($name, $origin, "PTR", $hostname);
155
2021-12-17
jrmu
}
156
2021-12-17
jrmu
# delete rdns of $ip6 given $subnet
157
2021-12-17
jrmu
# return true on success; false on failure
158
2021-12-17
jrmu
sub delrdns {
159
2021-12-17
jrmu
my ($ip6, $subnet) = @_;
160
2021-12-17
jrmu
return setrdns($ip6, $subnet);
161
2021-12-17
jrmu
}
162
2021-12-17
jrmu
163
2021-12-17
jrmu
# given $origin. create $name RR of $type and set to $value if provided;
164
2021-12-17
jrmu
# if $value is missing, delete $domain
165
2021-12-17
jrmu
# returns true upon success, false upon failure
166
2021-12-17
jrmu
sub setdns {
167
2021-12-17
jrmu
my ($name, $origin, $type, $value) = @_;
168
2021-12-17
jrmu
my $filename = "$zonedir/$origin";
169
2021-12-17
jrmu
my @lines = main::readarray($filename);
170
2021-12-17
jrmu
foreach my $line (@lines) {
171
2021-12-17
jrmu
# increment the zone's serial number
172
2021-12-17
jrmu
if ($line =~ /(\d{8})(\d{2})((\s+\d+){4}\s*\))/) {
173
2021-12-17
jrmu
my $date = main::date();
174
2021-12-17
jrmu
my $serial = 0;
175
2021-12-17
jrmu
if ($date <= $1) { $serial = $2+1; }
176
2021-12-17
jrmu
$line = $`.$date.sprintf("%02d",$serial).$3.$';
177
2021-12-17
jrmu
}
178
2021-12-17
jrmu
}
179
2021-12-17
jrmu
if (!defined($value)) { # delete records
180
2021-12-17
jrmu
@lines = grep !/\b$name\s*3600\s*IN/, @lines;
181
2021-12-17
jrmu
} else {
182
2021-12-17
jrmu
push(@lines, "$name 3600 IN $type $value");
183
2021-12-17
jrmu
}
184
2021-12-17
jrmu
# trailing newline necessary
185
2021-12-17
jrmu
main::writefile("$filename.bak", join("\n", @lines)."\n");
186
2021-12-17
jrmu
copy "$filename.bak", $filename;
187
2021-12-17
jrmu
if (system("doas -u _nsd nsd-control reload")) {
188
2021-12-17
jrmu
return 0;
189
2021-12-17
jrmu
} else {
190
2021-12-17
jrmu
return 1;
191
2021-12-17
jrmu
}
192
2021-12-17
jrmu
}
193
2021-12-17
jrmu
194
2021-12-17
jrmu
# given hostname, return IP addresses; or given IP address, return hostname
195
2021-12-17
jrmu
sub host {
196
2021-12-17
jrmu
my ($name) = @_;
197
2021-12-17
jrmu
my @matches;
198
2021-12-17
jrmu
my @lines = split /\n/m, `host $name`;
199
2021-12-17
jrmu
if ($name =~ /^[0-9\.]+$/ or $name =~ /:/) { # IP address
200
2021-12-17
jrmu
foreach my $line (@lines) {
201
2021-12-17
jrmu
if ($line =~ /([\d\.]+).(in-addr|ip6).arpa domain name pointer (.*)/) {
202
2021-12-17
jrmu
push(@matches, $3);
203
2021-12-17
jrmu
}
204
2021-12-17
jrmu
}
205
2021-12-17
jrmu
} else { # hostname
206
2021-12-17
jrmu
foreach my $line (@lines) {
207
2021-12-17
jrmu
if ($line =~ /$name has (IPv6 )?address ([0-9a-fA-F\.:]+)/) {
208
2021-12-17
jrmu
push(@matches, $2);
209
2021-12-17
jrmu
}
210
2021-12-17
jrmu
}
211
2021-12-17
jrmu
}
212
2021-12-17
jrmu
return join(' ', @matches);
213
2021-12-17
jrmu
}
214
2021-12-17
jrmu
215
2021-12-17
jrmu
# Return an ipv6 address with all zeroes filled in
216
2021-12-17
jrmu
sub ip6full {
217
2021-12-17
jrmu
my ($ip6) = @_;
218
2021-12-17
jrmu
my $left = substr($ip6, 0, index($ip6, "::"));
219
2021-12-17
jrmu
my $leftcolons = ($left =~ tr/://);
220
2021-12-17
jrmu
$ip6 =~ s{::}{:};
221
2021-12-17
jrmu
my @quartets = split(':', $ip6);
222
2021-12-17
jrmu
my $length = scalar(@quartets);
223
2021-12-17
jrmu
for (my $n = 1; $n <= 8 - $length; $n++) {
224
2021-12-17
jrmu
splice(@quartets, $leftcolons+1, 0, "0000");
225
2021-12-17
jrmu
}
226
2021-12-17
jrmu
my @newquartets = map(sprintf('%04s', $_), @quartets);
227
2021-12-17
jrmu
my $full = join(':',@newquartets);
228
2021-12-17
jrmu
return $full;
229
2021-12-17
jrmu
}
230
2021-12-17
jrmu
# Returns the network part of the first IPv6 address (indicated by subnet)
231
2021-12-17
jrmu
# with the host part of the second IPv6 address
232
2021-12-17
jrmu
sub ip6mask {
233
2021-12-17
jrmu
my ($ip6net, $subnet, $ip6host) = @_;
234
2021-12-17
jrmu
my $netdigits = ip6full($ip6net);
235
2021-12-17
jrmu
$netdigits =~ tr/://d;
236
2021-12-17
jrmu
my $hostdigits = ip6full($ip6host);
237
2021-12-17
jrmu
$hostdigits =~ tr/://d;
238
2021-12-17
jrmu
my $digits = substr($netdigits,0,($subnet/4)).substr($hostdigits,($subnet/4));
239
2021-12-17
jrmu
my $ip6;
240
2021-12-17
jrmu
for (my $n = 0; $n < 32; $n++) {
241
2021-12-17
jrmu
if ($n > 0 && $n % 4 == 0) {
242
2021-12-17
jrmu
$ip6 .= ":";
243
2021-12-17
jrmu
}
244
2021-12-17
jrmu
$ip6 .= substr($digits,$n,1);
245
2021-12-17
jrmu
}
246
2021-12-17
jrmu
return $ip6;
247
2021-12-17
jrmu
}
248
2021-12-17
jrmu
sub randip6 {
249
2021-12-17
jrmu
return join ':', map { sprintf '%04x', rand 0x10000 } (1 .. 8);
250
2021-12-17
jrmu
}
251
2021-12-17
jrmu
252
2021-12-17
jrmu
# create A and AAAA records for subdomain, set the rDNS,
253
2021-12-17
jrmu
# and return the new ipv6 address
254
2021-12-17
jrmu
sub nextdns {
255
2021-12-17
jrmu
my ($subdomain) = @_;
256
2021-12-17
jrmu
my $newip6 = $ip6;
257
2021-12-17
jrmu
my @allip6s = readip6s($hostnameif);
258
2021-12-17
jrmu
while (grep(/$newip6/, @allip6s)) {
259
2021-12-17
jrmu
$newip6 = ip6mask($ip6, $ip6subnet,randip6());
260
2021-12-17
jrmu
}
261
2021-12-17
jrmu
main::appendfile($hostnameif, "inet6 alias $newip6 48\n");
262
2021-12-17
jrmu
`doas ifconfig vio0 inet6 $newip6/48`;
263
2021-12-17
jrmu
if (setdns($subdomain, $hostname, "A", $ip4) && setdns($subdomain, $hostname, "AAAA", $newip6) && setrdns($newip6, $ip6subnet, "$subdomain.$hostname")) {
264
2021-12-17
jrmu
return "$newip6";
265
2021-12-17
jrmu
}
266
2021-12-17
jrmu
return "false";
267
2021-12-17
jrmu
}
268
2021-12-17
jrmu
269
2021-12-17
jrmu
1; # MUST BE LAST STATEMENT IN FILE
IRCNow