001// Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 
002// The Molly framework is freely distributable under the terms of an
003// MIT-style license. For details, see the molly pages web site at:
004// http://www.mollypages.org/. Use, modify, have fun !
005
006package fc.net;
007
008import java.io.*;
009import java.util.*;
010import java.util.regex.*;
011import java.nio.*;
012import java.nio.channels.*;
013import java.net.*;
014
015import fc.io.*;
016import fc.util.*;
017
018/**
019Network Interface Card related utility methods. Many of these
020methods are specific to ethernet type nic's.
021
022@author hursh jain
023**/
024public class NIC 
025{
026//for internal debugging
027private static boolean dbg = false;
028static String linesep = IOUtil.LINE_SEP;
029
030/**
031Returns a Map containing an IP address as the key and
032a {@link NIC.NICInfo} object as the value. Returns <tt>null</tt> if 
033the platform type is not supported.
034<p>
035<b>Note 1:</b> Requires a NT based system (NT, 2000, XP or later) if
036running on windows. (this call will not work for lesser versions of
037windows).<br>
038<b>Note 2:</b> An english locale is needed for this method to work
039properly (because we parse for certain english words to extract the 
040results).
041**/
042public static Map getMAC() 
043  {
044  Platform p = Platform.getPlatform();
045  try {
046    if (p == p.WINDOWS)   return getWindowsMA();  
047    else if (p == p.LINUX)  return getLinuxMA(); 
048    else if (p == p.OSX)   return getOSXMA(); 
049  
050  //we presume that linux stype ifconfig works identically
051  //on other plaforms. This of course is dicey at best.
052  //But I don't have no steeenkin bsd etc to test on.
053  
054    else if (p == p.FREEBSD) return getLinuxMA();
055    else if (p == p.OPENBSD) return getLinuxMA();
056    }
057  catch (IOException e) {
058    e.printStackTrace();
059    }
060  return null;
061  } 
062
063private static Map getWindowsMA() throws IOException
064  {
065  Map macs = new HashMap();
066  Process p = Runtime.getRuntime().exec("ipconfig /all");
067    InputStream in = p.getInputStream();
068    try {
069    String result = IOUtil.inputStreamToString(in, true);     
070    if (dbg) System.out.println("getWindowsMA(): " + linesep + "--------------- result ------------ " + linesep + result + linesep + "--------------------------------");
071    
072    //for some reason ^$ does not work properly (for blank lines)
073    //even when multiline mode is chosen
074    
075    Pattern pat = Pattern.compile(
076      "(?i)(?m)(?s)Ethernet\\s+adapter\\s+(.*?):.*?" +
077      "Physical\\s+Address.*?:\\s*([a-zA-Z0-9\\-]*).*?" +
078      "NetBIOS.*?:\\s*\\w*"
079      );
080
081    Pattern ip_pat = Pattern.compile(
082              "(?i)(?m)IP\\s+Address.*?:\\s+(.+?)$"
083             );
084    Matcher matcher = pat.matcher(result);
085    while (matcher.find()) {
086      if (dbg) System.out.println("getWindowsMA(): found: " + matcher.group(0));
087      String name = matcher.group(1);
088      String mac = matcher.group(2);
089      Matcher ipmatcher = ip_pat.matcher(matcher.group(0));
090      while (ipmatcher.find()) {
091        String ip = ipmatcher.group(1);
092        if (dbg) System.out.println("ip=" + ip + "; mac=" + mac + "; name=" + name);
093        NICInfo nicinfo = new NICInfo(name, mac);
094        macs.put(ip, nicinfo);  
095        }
096      }
097    } 
098  finally {
099    if ( in != null ) in.close();
100    }
101  return macs;
102    }
103
104private static Map getLinuxMA() throws IOException
105  {
106  Map macs = new HashMap();
107  Process p = Runtime.getRuntime().exec("ifconfig");
108    InputStream in = p.getInputStream();
109    try {
110    /*
111    //this should give us the entire input size but does NOT
112    //- instead returns 0 !
113    int resultlen = in.available();  
114    if (dbg) System.out.println("resultlen=" + resultlen);  
115    ReadableByteChannel bytechan = Channels.newChannel(in);
116    ByteBuffer bytebuf = ByteBuffer.allocate(resultlen);
117    bytechan.read(bytebuf); 
118    bytebuf.rewind();
119    if (dbg) System.out.println("ByteBuffer=" + bytebuf);               
120    CharBuffer cbuf = bytebuf.asCharBuffer(); 
121    if (dbg) System.out.println("CharBuffer=" + cbuf);                
122    */
123    
124    String result = IOUtil.inputStreamToString(in, true);
125
126    String pat = 
127      "(?s)(?m)(?i)(eth.*?)\\s+.+?HWaddr\\s([a-zA-Z0-9:\\-]*).*?addr:(.+?)\\s";       
128
129    Pattern linux_ifconfig_1_42 = Pattern.compile(pat);
130    Matcher matcher = linux_ifconfig_1_42.matcher(result);
131    while (matcher.find()) {
132      String name = matcher.group(1);
133      String mac = matcher.group(2);
134      String ip = matcher.group(3);
135      if (dbg) System.out.println("getLinuxMA(): found: " + matcher.group(0));
136      if (dbg) System.out.println("ip=" + ip + "; mac=" + mac + "; name=" + name);
137      NICInfo nicinfo = new NICInfo(name, mac);
138      macs.put(ip, nicinfo);  
139      }
140    } 
141  finally {
142    if ( in != null ) in.close();
143    }
144  return macs;
145    }
146
147
148private static Map getOSXMA() throws IOException
149  {
150  Map macs = new HashMap();
151  Process p = Runtime.getRuntime().exec("ifconfig");
152    InputStream in = p.getInputStream();
153    try {
154    String result = IOUtil.inputStreamToString(in, true);
155    String pat = "(?s)(?m)(?i)(en\\d+):.+?.*?status.*?$";       
156
157    Pattern osx = Pattern.compile(pat);
158    Matcher matcher = osx.matcher(result);
159
160    Pattern ip_pat = Pattern.compile( "(?i)inet\\s+([0-9.]+)\\s*" );
161    Pattern eth_pat = Pattern.compile( "(?i)ether\\s+([a-zA-Z0-9:\\-]*)\\s*" );
162
163    while (matcher.find()) 
164      {
165      String name = matcher.group(1);
166
167      if (dbg)  {
168        System.out.println("\n\n=========found: group[0]===========");
169        System.out.println(matcher.group(0));
170        System.out.println("\n==================");
171        }
172        
173      String mac = null;
174      String ip = null;
175
176      Matcher ip_matcher = ip_pat.matcher(matcher.group(0));
177      Matcher eth_matcher = eth_pat.matcher(matcher.group(0));
178      
179      if (ip_matcher.find()) {
180        ip = ip_matcher.group(1);
181        }
182
183      if (eth_matcher.find()) {
184        mac = eth_matcher.group(1);
185        }
186
187      if (dbg) System.out.println("ip=" + ip + "; mac=" + mac + "; name=" + name);
188      
189      if (ip != null && mac != null) {
190        NICInfo nicinfo = new NICInfo(name, mac);
191        macs.put(ip, nicinfo);
192        }
193      }
194    } 
195  finally {
196    if ( in != null ) in.close();
197    }
198  return macs;
199    }
200
201public static void main(String[] args) throws Exception
202  {
203  Args myargs = new Args(args);
204  if (myargs.flagExists("debug")) {
205    dbg = true;
206    }
207  System.out.println("[1] Mac Addresses: " + getMAC()); 
208  
209  System.out.println("\n[2] Using java networkinterface methods");  
210  Enumeration<NetworkInterface> infs = NetworkInterface.getNetworkInterfaces();
211  List list = Collections.list(infs);
212  for (int n = 0; n < list.size(); n++) {
213    NetworkInterface inf = (NetworkInterface) list.get(n);
214    System.out.println(
215      "name="+inf.getName()
216      +";ip="+Collections.list(inf.getInetAddresses())
217      +";hw="+inf.getHardwareAddress()
218      +";up="+inf.isUp());
219    }
220  }
221
222/** 
223Contains information about IP addresses and the associated
224interface names and MAC address. More than one IP address
225can be associated with the same interface.
226**/
227public static class NICInfo 
228{
229String interfaceName;
230String mac;
231 
232NICInfo(String interfaceName, String mac) {
233  this.interfaceName = interfaceName;
234  this.mac = mac; 
235  }
236/** 
237returns the name of the interface. This name may not
238be the same as the name returned by {@link NetworkInterface#getName} 
239(especially on windows).
240**/
241public String getInterfaceName() { return interfaceName; }
242
243/** returns the MAC address of the interface **/
244public String getMACAddress() { return mac; }
245
246public String toString() {
247  return "[NICInfo: name=" + interfaceName + "; MAC=" + mac + "]"; 
248  }
249} //~class NICInfo
250
251
252}  //~class NIC