2009-05-12

getting your ip-address

A friend asked me how to retrieve your IP-number in emacs; he needs it to figure out in which of various networks he lives, to update proxy settings and the like. He had found a decade-old function get-ip-address on the internet, and thought (correctly!) that it can't be that hard.

So, fortunately, it wasn't too hard to do it a bit better, esp. with all the improvements in emacs in the last ten years.

The somewhat-ugly-but-it-works solution is to use the output of the ifconfig tool:

(defun get-ip-address (&optional dev)
  "get the IP-address for device DEV (default: eth0)"
  (let ((dev (if dev dev "eth0"))) 
    (substring  ;; chop the final "\n"
      (shell-command-to-string
        (concat 
          "ifconfig " dev
          "|grep 'inet addr'|sed 's/.*inet addr:\\(\\([0-9\.]\\)*\\).*/\\1/'"))
      0 -1)))
Now, calling (get-ip-address "eth0") or (get-ip-address "lo") in your scripts will get you the IP-number. Obviously, this only works on systems that have this ifconfig, and is also vulnerable to small changes in the output. Don't even ask about IPv6.

The solution does give us a nice example of using shell-command-to-string, which is really useful function to integrate with all kinds of external tools; the difference with decade-old get=ip-address is striking.

However, we can do even better in these modern times. More recent versions of emacs provide nice networking functionality:

(defun get-ip-address (&optional dev)
  "get the IP-address for device DEV (default: eth0)"
  (let ((dev (if dev dev "eth0"))) 
    (format-network-address (car (network-interface-info dev)) t)))
All fine - but unfortunately, this does not work on Windows; there is no such thing as network-interface-info there, not even in the latest Emacs incarnations. Is there nothing else we can do on Windows? Well… we can go back to the first solution (using shell-command-to-string, and see if we can use it with Windows' ipconfig tool. Something like:
(defun get-ip-address () 
  "Win32: get the IP-address of the first network interface"
  (let ((ipconfig (shell-command-to-string "ipconfig | findstr Address"))) 
    (string-match "\\(\\([0-9]+.\\)+[0-9]+\\)" ipconfig)
    (match-string 0 ipconfig)))
The Windows version does not support choosing the interface; I'll leave that as an excercise to a reader with some more Win-fu; that same reader might also have a solution that does not involve ipconfig, but uses some Win32-API. And of course, that user is invited to help the emacs development team to add a Win32 version of network-interface-info.

4 comments:

Anonymous said...

Hello, yrk here,

"M-x ifconfig" is a part of emacs already. It is also aliased to "ipconfig".

It also has some font-locking regular expressions which might make the above easier.

djcb said...

@Anonymous: ah, didn't know that one.

it does not solve the 'get me my ip address' problem though; running either ifconfig or ipconfig is the easy part.

Anonymous said...

...and windows loves giving the result in local language so the simple grep for "address" does not work for all, (I'm running multiple machines with different languages)...

muthu said...

Nice Article.M-x ifconfig" is a part of emacs already.it does not solve the 'get me my ip address' problem though; running either ifconfig or ipconfig is the easy part.And Get my internet ipaddress in the www.ip-details.com.