aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeder O. Klingenberg2017-05-23 20:34:08 -0400
committerGlenn Morris2017-05-23 20:34:08 -0400
commit8f6550b38c8b467a8f26c63050bd842f4fdc0b1e (patch)
tree5c33e5238776ff33a2f7bb004eca88afffadcd3b
parentef9f5c672a8e248dd7bd682101c03feb2e527340 (diff)
downloademacs-8f6550b38c8b467a8f26c63050bd842f4fdc0b1e.tar.gz
emacs-8f6550b38c8b467a8f26c63050bd842f4fdc0b1e.zip
New dns-mode command for IPv6 address conversion
This converts IPv6 addresses to a format suitable for reverse lookup zone files. (Bug#26820) * lisp/textmodes/dns-mode.el (dns-mode-map, dns-mode-menu): Add dns-mode-ipv6-to-nibbles. (dns-mode-ipv6-to-nibbles, dns-mode-reverse-and-expand-ipv6): New functions. * test/lisp/dns-mode-tests.el: New file. ; * etc/NEWS: Mention this.
-rw-r--r--etc/NEWS4
-rw-r--r--lisp/textmodes/dns-mode.el99
-rw-r--r--test/lisp/dns-mode-tests.el58
3 files changed, 160 insertions, 1 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 2ca91d5d793..2a7c48d8119 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -850,6 +850,10 @@ This is done with the help of 'c-or-c++-mode' function which analyses
850contents of the buffer to determine whether it's a C or C++ source 850contents of the buffer to determine whether it's a C or C++ source
851file. 851file.
852 852
853---
854** New DNS mode command 'dns-mode-ipv6-to-nibbles' to convert IPv6 addresses
855to a format suitable for reverse lookup zone files.
856
853** Flymake 857** Flymake
854 858
855+++ 859+++
diff --git a/lisp/textmodes/dns-mode.el b/lisp/textmodes/dns-mode.el
index cc8bad6337b..7bdadbfe6f1 100644
--- a/lisp/textmodes/dns-mode.el
+++ b/lisp/textmodes/dns-mode.el
@@ -147,6 +147,7 @@ manually with \\[dns-mode-soa-increment-serial]."
147(defvar dns-mode-map 147(defvar dns-mode-map
148 (let ((map (make-sparse-keymap))) 148 (let ((map (make-sparse-keymap)))
149 (define-key map "\C-c\C-s" 'dns-mode-soa-increment-serial) 149 (define-key map "\C-c\C-s" 'dns-mode-soa-increment-serial)
150 (define-key map "\C-c\C-e" 'dns-mode-ipv6-to-nibbles)
150 map) 151 map)
151 "Keymap for DNS master file mode.") 152 "Keymap for DNS master file mode.")
152 153
@@ -158,7 +159,8 @@ manually with \\[dns-mode-soa-increment-serial]."
158(easy-menu-define dns-mode-menu dns-mode-map 159(easy-menu-define dns-mode-menu dns-mode-map
159 "DNS Menu." 160 "DNS Menu."
160 '("DNS" 161 '("DNS"
161 ["Increment SOA serial" dns-mode-soa-increment-serial t])) 162 ["Increment SOA serial" dns-mode-soa-increment-serial t]
163 ["Convert IPv6 address to nibbles" dns-mode-ipv6-to-nibbles t]))
162 164
163;; Mode. 165;; Mode.
164 166
@@ -254,6 +256,101 @@ This function is run from `before-save-hook'."
254 ;; We return nil in case this is used in write-contents-functions. 256 ;; We return nil in case this is used in write-contents-functions.
255 nil))) 257 nil)))
256 258
259;;;###autoload
260(defun dns-mode-ipv6-to-nibbles (&optional negate-prefix)
261 "Convert an IPv6 address around or before point.
262Replace the address by its ip6.arpa-representation for use in
263reverse zone files, placing the original address in the kill ring.
264
265The address can be: a complete address (no prefix designator);
266with a normal prefix designator (e.g. /48), in which case only
267the required number of nibbles are output; or with a negative
268prefix designator (e.g. /-112), in which case only the part of
269the address *not* covered by the absolute value of the prefix
270length is output, as a relative address (without \".ip6.arpa.\" at
271the end). This is useful when $ORIGIN is specified in the zone file.
272
273Optional prefix argument NEGATE-PREFIX negates the value of the
274detected prefix length.
275
276Examples:
277
2782001:db8::12 =>
2792.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
280
2812001:db8::12/32 =>
2828.b.d.0.1.0.0.2.ip6.arpa.
283
2842001:db8::12/-32 =>
2852.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0
286
287::42/112 (with prefix argument) =>
2882.4.0.0"
289 (interactive "P")
290 (skip-syntax-backward " ")
291 (skip-syntax-backward "w_.")
292 (re-search-forward "\\([[:xdigit:]:]+\\)\\(/-?[0-9]\\{2,3\\}\\)?")
293 (kill-new (match-string 0))
294 (let ((address (match-string 1))
295 (prefix-length (match-string 2)))
296 (when prefix-length
297 (setq prefix-length (string-to-number (substring prefix-length 1)))
298 (if negate-prefix
299 (setq prefix-length (- prefix-length))))
300 (replace-match
301 (save-match-data
302 (dns-mode-reverse-and-expand-ipv6 address prefix-length)))))
303
304(defun dns-mode-reverse-and-expand-ipv6 (address &optional prefix-length)
305 "Convert an IPv6 address to (parts of) an ip6.arpa nibble format.
306ADDRESS is an IPv6 address in the usual colon-separated
307format, without a prefix designator at the end.
308
309Optional PREFIX-LENGTH is a number whose absolute value is the
310length in bits of the network part of the address. If nil,
311return an absolute address representing the full IPv6 address.
312If positive, return an absolute address representing the network
313prefix indicated. If negative, return a relative address
314representing the host parts of the address with respect to the
315indicated network prefix.
316
317See `dns-mode-ipv6-to-nibbles' for examples."
318 (let* ((chunks (split-string address ":"))
319 (prefix-length-nibbles (if prefix-length
320 (ceiling (abs prefix-length) 4)
321 32))
322 (filler-chunks (- 8 (length (remove "" chunks))))
323 (expanded-address
324 (apply #'concat
325 (cl-loop with filler-done = nil
326 for chunk in chunks
327 if (and (not filler-done)
328 (string= "" chunk))
329 append (prog1
330 (cl-loop repeat filler-chunks
331 collect "0000")
332 (setq filler-done t))
333 else
334 if (not (string= "" chunk))
335 collect (format "%04x"
336 (string-to-number chunk 16)))))
337 (rev-address-nibbles
338 (nreverse (if (and prefix-length
339 (cl-minusp prefix-length))
340 (substring expanded-address prefix-length-nibbles)
341 (substring expanded-address 0 prefix-length-nibbles)))))
342 (with-temp-buffer
343 (cl-loop for char across rev-address-nibbles
344 do
345 (insert char)
346 (insert "."))
347 (if (and prefix-length
348 (cl-minusp prefix-length))
349 (delete-char -1)
350 (insert "ip6.arpa."))
351 (insert " ")
352 (buffer-string))))
353
257(provide 'dns-mode) 354(provide 'dns-mode)
258 355
259;;; dns-mode.el ends here 356;;; dns-mode.el ends here
diff --git a/test/lisp/dns-mode-tests.el b/test/lisp/dns-mode-tests.el
new file mode 100644
index 00000000000..34e86201d82
--- /dev/null
+++ b/test/lisp/dns-mode-tests.el
@@ -0,0 +1,58 @@
1;;; dns-mode-tests.el --- Test suite for dns-mode -*- lexical-binding: t; -*-
2
3;; Copyright (C) 2017 Free Software Foundation, Inc.
4
5;; Author: Peder O. Klingenberg <peder@klingenberg.no>
6;; Keywords: dns zone
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software: you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
22
23;;; Code:
24
25(require 'ert)
26(require 'dns-mode)
27
28;;; IPv6 reverse zones
29(ert-deftest dns-mode-ipv6-conversion ()
30 (let ((address "2001:db8::42"))
31 (should (equal (dns-mode-reverse-and-expand-ipv6 address)
32 "2.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. "))
33 (should (equal (dns-mode-reverse-and-expand-ipv6 address 32)
34 "8.b.d.0.1.0.0.2.ip6.arpa. "))
35 (should (equal (dns-mode-reverse-and-expand-ipv6 address -112)
36 "2.4.0.0 "))))
37
38(ert-deftest dns-mode-ipv6-text-replacement ()
39 (let ((address "2001:db8::42/32"))
40 (with-temp-buffer
41 ;; Conversion with point directly after address
42 (insert address)
43 (dns-mode-ipv6-to-nibbles nil)
44 (should (equal (buffer-string) "8.b.d.0.1.0.0.2.ip6.arpa. "))
45 ;; Kill ring contains the expected
46 (erase-buffer)
47 (yank)
48 (should (equal (buffer-string) address))
49 ;; Point at beginning of address (and prefix arg to command)
50 (goto-char (point-min))
51 (dns-mode-ipv6-to-nibbles t)
52 (should (equal (buffer-string) "2.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 "))
53 ;; Point separated from address by whitespace
54 (erase-buffer)
55 (insert address)
56 (insert " ")
57 (dns-mode-ipv6-to-nibbles nil)
58 (should (equal (buffer-string) "8.b.d.0.1.0.0.2.ip6.arpa. ")))))