.
[emacs.git] / lisp / net-utils.el
blob08aab61f6c8bcbb075fee1aff02f2e874c74bb5c
1 ;;; net-utils.el --- Network functions
3 ;; Author: Peter Breton <pbreton@cs.umb.edu>
4 ;; Created: Sun Mar 16 1997
5 ;; Keywords: network communications
6 ;; Time-stamp: <1998-06-13 06:19:01 pbreton>
8 ;; This file is part of GNU Emacs.
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 2, or (at your option)
13 ;; any later version.
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.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
25 ;;; Commentary:
27 ;; There are three main areas of functionality:
28 ;;
29 ;; * Wrap common network utility programs (ping, traceroute, netstat,
30 ;; nslookup, arp, route). Note that these wrappers are of the diagnostic
31 ;; functions of these programs only.
32 ;;
33 ;; * Implement some very basic protocols in Emacs Lisp (finger and whois)
34 ;;
35 ;; * Support connections to HOST/PORT, generally for debugging and the like.
36 ;; In other words, for doing much the same thing as "telnet HOST PORT", and
37 ;; then typing commands.
39 ;; PATHS
41 ;; On some systems, some of these programs are not in normal user path,
42 ;; but rather in /sbin, /usr/sbin, and so on.
45 ;;; Code:
46 (eval-when-compile
47 (require 'comint))
49 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
50 ;; Customization Variables
51 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
53 (defgroup net-utils nil
54 "Network utility functions."
55 :prefix "net-utils-"
56 :group 'comm
57 :version "20.3"
60 (defcustom net-utils-remove-ctl-m
61 (member system-type (list 'windows-nt 'msdos))
62 "If non-nil, remove control-Ms from output."
63 :group 'net-utils
64 :type 'boolean
67 (defcustom traceroute-program
68 (if (eq system-type 'windows-nt)
69 "tracert"
70 "traceroute")
71 "Program to trace network hops to a destination."
72 :group 'net-utils
73 :type 'string
76 (defcustom traceroute-program-options nil
77 "Options for the traceroute program."
78 :group 'net-utils
79 :type '(repeat string)
82 (defcustom ping-program "ping"
83 "Program to send network test packets to a host."
84 :group 'net-utils
85 :type 'string
88 ;; On Linux and Irix, the system's ping program seems to send packets
89 ;; indefinitely unless told otherwise
90 (defcustom ping-program-options
91 (and (memq system-type (list 'linux 'gnu/linux 'irix))
92 (list "-c" "4"))
93 "Options for the ping program.
94 These options can be used to limit how many ICMP packets are emitted."
95 :group 'net-utils
96 :type '(repeat string)
99 (defcustom ipconfig-program
100 (if (eq system-type 'windows-nt)
101 "ipconfig"
102 "ifconfig")
103 "Program to print network configuration information."
104 :group 'net-utils
105 :type 'string
108 (defcustom ipconfig-program-options
109 (list
110 (if (eq system-type 'windows-nt)
111 "/all" "-a"))
112 "Options for ipconfig-program."
113 :group 'net-utils
114 :type '(repeat string)
117 (defcustom netstat-program "netstat"
118 "Program to print network statistics."
119 :group 'net-utils
120 :type 'string
123 (defcustom netstat-program-options
124 (list "-a")
125 "Options for netstat-program."
126 :group 'net-utils
127 :type '(repeat string)
130 (defcustom arp-program "arp"
131 "Program to print IP to address translation tables."
132 :group 'net-utils
133 :type 'string
136 (defcustom arp-program-options
137 (list "-a")
138 "Options for arp-program."
139 :group 'net-utils
140 :type '(repeat string)
143 (defcustom route-program
144 (if (eq system-type 'windows-nt)
145 "route"
146 "netstat")
147 "Program to print routing tables."
148 :group 'net-utils
149 :type 'string
152 (defcustom route-program-options
153 (if (eq system-type 'windows-nt)
154 (list "print")
155 (list "-r"))
156 "Options for route-program."
157 :group 'net-utils
158 :type '(repeat string)
161 (defcustom nslookup-program "nslookup"
162 "Program to interactively query DNS information."
163 :group 'net-utils
164 :type 'string
167 (defcustom nslookup-program-options nil
168 "List of options to pass to the nslookup program."
169 :group 'net-utils
170 :type '(repeat string)
173 (defcustom nslookup-prompt-regexp "^> "
174 "Regexp to match the nslookup prompt."
175 :group 'net-utils
176 :type 'regexp
179 (defcustom ftp-program "ftp"
180 "Progam to run to do FTP transfers."
181 :group 'net-utils
182 :type 'string
185 (defcustom ftp-program-options nil
186 "List of options to pass to the FTP program."
187 :group 'net-utils
188 :type '(repeat string)
191 (defcustom ftp-prompt-regexp "^ftp>"
192 "Regexp which matches the FTP program's prompt."
193 :group 'net-utils
194 :type 'regexp
197 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
198 ;; Nslookup goodies
199 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
201 (defconst nslookup-font-lock-keywords
202 (and window-system
203 (progn
204 (require 'font-lock)
205 (list
206 (list nslookup-prompt-regexp 0 font-lock-reference-face)
207 (list "^[A-Za-z0-9 _]+:" 0 font-lock-type-face)
208 (list "\\<\\(SOA\\|NS\\|MX\\|A\\|CNAME\\)\\>"
209 1 font-lock-keyword-face)
210 ;; Dotted quads
211 (list
212 (mapconcat 'identity
213 (make-list 4 "[0-9]+")
214 "\\.")
215 0 font-lock-variable-name-face)
216 ;; Host names
217 (list
218 (let ((host-expression "[-A-Za-z0-9]+"))
219 (concat
220 (mapconcat 'identity
221 (make-list 2 host-expression)
222 "\\.")
223 "\\(\\." host-expression "\\)*")
225 0 font-lock-variable-name-face)
227 "Expressions to font-lock for nslookup.")
229 (defvar nslookup-abbrev-table (make-abbrev-table)
230 "Abbrev table for nslookup.")
232 (define-abbrev nslookup-abbrev-table "e" "exit")
233 (define-abbrev nslookup-abbrev-table "f" "finger")
234 (define-abbrev nslookup-abbrev-table "h" "help")
235 (define-abbrev nslookup-abbrev-table "lse" "lserver")
236 (define-abbrev nslookup-abbrev-table "r" "root")
237 (define-abbrev nslookup-abbrev-table "s" "set")
238 (define-abbrev nslookup-abbrev-table "se" "server")
239 (define-abbrev nslookup-abbrev-table "v" "viewer")
241 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
242 ;; FTP goodies
243 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
245 (defvar ftp-abbrev-table (make-abbrev-table)
246 "Abbrev table for ftp.")
248 (define-abbrev ftp-abbrev-table "q" "quit")
249 (define-abbrev ftp-abbrev-table "g" "get")
250 (define-abbrev ftp-abbrev-table "p" "prompt")
251 (define-abbrev ftp-abbrev-table "anon" "anonymous")
253 (defconst ftp-font-lock-keywords
254 (and window-system
255 (progn
256 (require 'font-lock)
257 (list
258 (list ftp-prompt-regexp 0 font-lock-reference-face)))))
261 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
262 ;; Utility functions
263 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
265 ;; Simplified versions of some at-point functions from ffap.el.
266 ;; It's not worth loading all of ffap just for these.
267 (defun net-utils-machine-at-point ()
268 (let ((pt (point)))
269 (buffer-substring-no-properties
270 (save-excursion
271 (skip-chars-backward "-a-zA-Z0-9.")
272 (point))
273 (save-excursion
274 (skip-chars-forward "-a-zA-Z0-9.")
275 (skip-chars-backward "." pt)
276 (point)))))
278 (defun net-utils-url-at-point ()
279 (let ((pt (point)))
280 (buffer-substring-no-properties
281 (save-excursion
282 (skip-chars-backward "--:=&?$+@-Z_a-z~#,%")
283 (skip-chars-forward "^A-Za-z0-9" pt)
284 (point))
285 (save-excursion
286 (skip-chars-forward "--:=&?$+@-Z_a-z~#,%")
287 (skip-chars-backward ":;.,!?" pt)
288 (point)))))
291 (defun net-utils-remove-ctrl-m-filter (process output-string)
292 "Remove trailing control Ms."
293 (let ((old-buffer (current-buffer))
294 (filtered-string output-string))
295 (unwind-protect
296 (let ((moving))
297 (set-buffer (process-buffer process))
298 (setq moving (= (point) (process-mark process)))
300 (while (string-match "\r" filtered-string)
301 (setq filtered-string
302 (replace-match "" nil nil filtered-string)))
304 (save-excursion
305 ;; Insert the text, moving the process-marker.
306 (goto-char (process-mark process))
307 (insert filtered-string)
308 (set-marker (process-mark process) (point)))
309 (if moving (goto-char (process-mark process))))
310 (set-buffer old-buffer))))
312 (defmacro net-utils-run-program (name header program &rest args)
313 "Run a network information program."
315 (let ((buf (get-buffer-create (concat "*" (, name) "*"))))
316 (set-buffer buf)
317 (erase-buffer)
318 (insert (, header) "\n")
319 (set-process-filter
320 (apply 'start-process (, name) buf (, program) (,@ args))
321 'net-utils-remove-ctrl-m-filter)
322 (display-buffer buf))))
324 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
325 ;; Wrappers for external network programs
326 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
328 ;;;###autoload
329 (defun traceroute (target)
330 "Run traceroute program for TARGET."
331 (interactive "sTarget: ")
332 (let ((options
333 (if traceroute-program-options
334 (append traceroute-program-options (list target))
335 (list target))))
336 (net-utils-run-program
337 (concat "Traceroute" " " target)
338 (concat "** Traceroute ** " traceroute-program " ** " target)
339 traceroute-program
340 options
343 ;;;###autoload
344 (defun ping (host)
345 "Ping HOST.
346 If your system's ping continues until interrupted, you can try setting
347 `ping-program-options'."
348 (interactive
349 (list (read-from-minibuffer "Ping host: " (net-utils-machine-at-point))))
350 (let ((options
351 (if ping-program-options
352 (append ping-program-options (list host))
353 (list host))))
354 (net-utils-run-program
355 (concat "Ping" " " host)
356 (concat "** Ping ** " ping-program " ** " host)
357 ping-program
358 options
361 ;;;###autoload
362 (defun ipconfig ()
363 "Run ipconfig program."
364 (interactive)
365 (net-utils-run-program
366 "Ipconfig"
367 (concat "** Ipconfig ** " ipconfig-program " ** ")
368 ipconfig-program
369 ipconfig-program-options
372 ;; This is the normal name on most Unixes.
373 ;;;###autoload
374 (defalias 'ifconfig 'ipconfig)
376 ;;;###autoload
377 (defun netstat ()
378 "Run netstat program."
379 (interactive)
380 (net-utils-run-program
381 "Netstat"
382 (concat "** Netstat ** " netstat-program " ** ")
383 netstat-program
384 netstat-program-options
387 ;;;###autoload
388 (defun arp ()
389 "Run the arp program."
390 (interactive)
391 (net-utils-run-program
392 "Arp"
393 (concat "** Arp ** " arp-program " ** ")
394 arp-program
395 arp-program-options
398 ;;;###autoload
399 (defun route ()
400 "Run the route program."
401 (interactive)
402 (net-utils-run-program
403 "Route"
404 (concat "** Route ** " route-program " ** ")
405 route-program
406 route-program-options
409 ;; FIXME -- Needs to be a process filter
410 ;; (defun netstat-with-filter (filter)
411 ;; "Run netstat program."
412 ;; (interactive "sFilter: ")
413 ;; (netstat)
414 ;; (set-buffer (get-buffer "*Netstat*"))
415 ;; (goto-char (point-min))
416 ;; (delete-matching-lines filter)
417 ;; )
419 ;;;###autoload
420 (defun nslookup-host (host)
421 "Lookup the DNS information for HOST."
422 (interactive
423 (list (read-from-minibuffer "Lookup host: " (net-utils-machine-at-point))))
424 (let ((options
425 (if nslookup-program-options
426 (append nslookup-program-options (list host))
427 (list host))))
428 (net-utils-run-program
429 "Nslookup"
430 (concat "** "
431 (mapconcat 'identity
432 (list "Nslookup" host nslookup-program)
433 " ** "))
434 nslookup-program
435 options
439 ;;;###autoload
440 (defun nslookup ()
441 "Run nslookup program."
442 (interactive)
443 (require 'comint)
444 (comint-run nslookup-program)
445 (set-process-filter (get-buffer-process "*nslookup*")
446 'net-utils-remove-ctrl-m-filter)
447 (set
448 (make-local-variable 'font-lock-defaults)
449 '((nslookup-font-lock-keywords)))
450 (set
451 (make-local-variable 'local-abbrev-table)
452 nslookup-abbrev-table)
453 (abbrev-mode t)
454 (make-local-variable 'comint-prompt-regexp)
455 (setq comint-prompt-regexp nslookup-prompt-regexp)
458 ;; This is a lot less than ange-ftp, but much simpler.
459 ;;;###autoload
460 (defun ftp (host)
461 "Run ftp program."
462 (interactive "sFtp to Host: ")
463 (require 'comint)
464 (let ((buf (get-buffer-create (concat "*ftp [" host "]*"))))
465 (set-buffer buf)
466 (comint-mode)
467 (comint-exec buf (concat "ftp-" host) ftp-program nil
468 (if ftp-program-options
469 (append (list host) ftp-program-options)
470 (list host)))
471 (set
472 (make-local-variable 'font-lock-defaults)
473 '((ftp-font-lock-keywords)))
475 (make-local-variable 'comint-prompt-regexp)
476 (setq comint-prompt-regexp ftp-prompt-regexp)
478 ;; Already buffer local!
479 (setq comint-output-filter-functions
480 (list 'comint-watch-for-password-prompt))
481 (set
482 (make-local-variable 'local-abbrev-table)
483 ftp-abbrev-table)
484 (abbrev-mode t)
485 (switch-to-buffer-other-window buf)
488 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
489 ;; Network Connections
490 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
492 ;; Full list is available at:
493 ;; ftp://ftp.isi.edu/in-notes/iana/assignments/port-numbers
494 (defvar network-connection-service-alist
495 (list
496 (cons 'echo 7)
497 (cons 'active-users 11)
498 (cons 'daytime 13)
499 (cons 'chargen 19)
500 (cons 'ftp 21)
501 (cons 'telnet 23)
502 (cons 'smtp 25)
503 (cons 'time 37)
504 (cons 'whois 43)
505 (cons 'gopher 70)
506 (cons 'finger 79)
507 (cons 'www 80)
508 (cons 'pop2 109)
509 (cons 'pop3 110)
510 (cons 'sun-rpc 111)
511 (cons 'nntp 119)
512 (cons 'ntp 123)
513 (cons 'netbios-name 137)
514 (cons 'netbios-data 139)
515 (cons 'irc 194)
516 (cons 'https 443)
517 (cons 'rlogin 513)
519 "Alist of services and associated TCP port numbers.
520 This list in not complete.")
522 ;; Workhorse macro
523 (defmacro run-network-program (process-name host port
524 &optional initial-string)
526 (let ((tcp-connection)
527 (buf)
529 (setq buf (get-buffer-create (concat "*" (, process-name) "*")))
530 (set-buffer buf)
531 (or
532 (setq tcp-connection
533 (open-network-stream
534 (, process-name)
536 (, host)
537 (, port)
539 (error "Could not open connection to %s" (, host)))
540 (erase-buffer)
541 (set-marker (process-mark tcp-connection) (point-min))
542 (set-process-filter tcp-connection 'net-utils-remove-ctrl-m-filter)
543 (and (, initial-string)
544 (process-send-string tcp-connection
545 (concat (, initial-string) "\r\n")))
546 (display-buffer buf))))
548 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
549 ;; Simple protocols
550 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
552 ;; Finger protocol
553 ;;;###autoload
554 (defun finger (user host)
555 "Finger USER on HOST."
556 ;; One of those great interactive statements that's actually
557 ;; longer than the function call! The idea is that if the user
558 ;; uses a string like "pbreton@cs.umb.edu", we won't ask for the
559 ;; host name. If we don't see an "@", we'll prompt for the host.
560 (interactive
561 (let* ((answer (read-from-minibuffer "Finger User: "
562 (net-utils-url-at-point)))
563 (index (string-match "@" answer)))
564 (if index
565 (list
566 (substring answer 0 index)
567 (substring answer (1+ index)))
568 (list
569 answer
570 (read-from-minibuffer "At Host: " (net-utils-machine-at-point))))))
571 (run-network-program
572 (concat "Finger [" user "@" host "]")
573 host
574 (cdr (assoc 'finger network-connection-service-alist))
575 user))
577 (defcustom whois-server-name "whois.arin.net"
578 "Default host name for the whois service."
579 :group 'net-utils
580 :type 'string
583 (defcustom whois-server-list
584 '(("whois.arin.net") ; Networks, ASN's, and related POC's (numbers)
585 ("rs.internic.net") ; domain related info
586 ("whois.abuse.net")
587 ("whois.apnic.net")
588 ("nic.ddn.mil")
589 ("whois.nic.mil")
590 ("whois.nic.gov")
591 ("whois.ripe.net"))
592 "A list of whois servers that can be queried."
593 :group 'net-utils
594 :type '(repeat (list string)))
596 (defcustom whois-server-tld
597 '(("rs.internic.net" . "com")
598 ("rs.internic.net" . "org")
599 ("whois.ripe.net" . "be")
600 ("whois.ripe.net" . "de")
601 ("whois.ripe.net" . "dk")
602 ("whois.ripe.net" . "it")
603 ("whois.ripe.net" . "fi")
604 ("whois.ripe.net" . "fr")
605 ("whois.ripe.net" . "uk")
606 ("whois.apnic.net" . "au")
607 ("whois.apnic.net" . "ch")
608 ("whois.apnic.net" . "hk")
609 ("whois.apnic.net" . "jp")
610 ("whois.nic.gov" . "gov")
611 ("whois.nic.mil" . "mil"))
612 "Alist to map top level domains to whois servers."
613 :group 'net-utils
614 :type '(repeat (cons string string)))
616 (defcustom whois-guess-server t
617 "If non-nil then whois will try to deduce the appropriate whois
618 server from the query. If the query doesn't look like a domain or hostname
619 then the server named by whois-server-name is used."
620 :group 'net-utils
621 :type 'boolean)
623 (defun whois-get-tld (host)
624 "Return the top level domain of `host', or nil if it isn't a domain name."
625 (let ((i (1- (length host)))
626 (max-len (- (length host) 5)))
627 (while (not (or (= i max-len) (char-equal (aref host i) ?.)))
628 (setq i (1- i)))
629 (if (= i max-len)
631 (substring host (1+ i)))))
633 ;; Whois protocol
634 ;;;###autoload
635 (defun whois (arg search-string)
636 "Send SEARCH-STRING to server defined by the `whois-server-name' variable.
637 If `whois-guess-server' is non-nil, then try to deduce the correct server
638 from SEARCH-STRING. With argument, prompt for whois server."
639 (interactive "P\nsWhois: ")
640 (let* ((whois-apropos-host (if whois-guess-server
641 (rassoc (whois-get-tld search-string)
642 whois-server-tld)
643 nil))
644 (server-name (if whois-apropos-host
645 (car whois-apropos-host)
646 whois-server-name))
647 (host
648 (if arg
649 (completing-read "Whois server name: "
650 whois-server-list nil nil "whois.")
651 server-name)))
652 (run-network-program
653 "Whois"
654 host
655 (cdr (assoc 'whois network-connection-service-alist))
656 search-string
659 (defcustom whois-reverse-lookup-server "whois.arin.net"
660 "Server which provides inverse DNS mapping."
661 :group 'net-utils
662 :type 'string
665 ;;;###autoload
666 (defun whois-reverse-lookup ()
667 (interactive)
668 (let ((whois-server-name whois-reverse-lookup-server))
669 (call-interactively 'whois)))
671 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
672 ;;; General Network connection
673 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
675 ;;;###autoload
676 (defun network-connection-to-service (host service)
677 "Open a network connection to SERVICE on HOST."
678 (interactive
679 (list
680 (read-from-minibuffer "Host: " (net-utils-machine-at-point))
681 (completing-read "Service: "
682 (mapcar
683 (function
684 (lambda (elt)
685 (list (symbol-name (car elt)))))
686 network-connection-service-alist))))
687 (network-connection
688 host
689 (cdr (assoc (intern service) network-connection-service-alist)))
692 ;;;###autoload
693 (defun network-connection (host port)
694 "Open a network connection to HOST on PORT."
695 (interactive "sHost: \nnPort: ")
696 (network-service-connection host (number-to-string port)))
698 (defun network-service-connection (host service)
699 "Open a network connection to SERVICE on HOST."
700 (require 'comint)
701 (let (
702 (process-name (concat "Network Connection [" host " " service "]"))
703 (portnum (string-to-number service))
705 (or (zerop portnum) (setq service portnum))
706 (make-comint
707 process-name
708 (cons host service))
709 (pop-to-buffer (get-buffer (concat "*" process-name "*")))
712 (provide 'net-utils)
714 ;;; net-utils.el ends here