Получаем локальный IP и Mac посетителя на сайте

Возникла задача: необходимо записать в лог, с какого локального (внутреннего) IP и MAC (на случай включенного DHCP внутри подсетки)  адресов клиент зашел на сайт. Если разбирать заголовки запроса на сервере, то мы получим лишь его внешний IP. Если пользователь сидит за NAT’ом, то это нам практически ничего не даст.  Что же делать? Запускать что-то на клиенте, что обратится к его сетевой карте и получит все необходимые сведения, а затем передаст на сервер. Первым в голову приходит JavaScript, но вот беда — из-за ограничений безопасности браузера JS не может получить доступа к железу. Значит, будем пробовать реализовать это на JAVA, добавив в страничку невидимый апплет.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class IPControl extends Applet {
 
    private String IpLog = new String();
    private String MacLog = new String();
 
    public String getMacLog() {
        return MacLog;
    }
 
    public String getIpLog() {
        return this.IpLog;
    }
 
    private void setIpLog() {
        String regexp = "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$";
        String IP;
        String Mac;
        boolean IsValid;
        try {
            Enumeration n = NetworkInterface.getNetworkInterfaces();
            for (; n.hasMoreElements();) {
                NetworkInterface e = n.nextElement();
                Enumeration a = e.getInetAddresses();
                for (; a.hasMoreElements();) {
                    InetAddress addr = a.nextElement();
                    IP = addr.getHostAddress();
                    IsValid = Pattern.matches(regexp, IP);
                    if (IsValid) {
                        byte m[] = e.getHardwareAddress();
                        StringBuilder sb = new StringBuilder(18);
                        for (byte b : m) {
                            if (sb.length() > 0)
                                sb.append('-');
                            sb.append(String.format("%02x", b));
                        }
                        Mac = sb.toString();
                        if(IP.equals("127.0.0.1")) continue;
                        this.IpLog += "IP:" + IP + ",";
                        this.MacLog += "MAC:" + Mac + ",";
                    }
                }
            }
        } catch (SocketException ex) {
            Logger.getLogger(IPControl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
 
    public void init()
    {
        setIpLog();
    }
}

Основную логику апплета выполняет метод setIpLog. В нем в цикле обходятся все сетевые интерфейсы клиента, затем «выкидываются» те, что не имеют адреса вида «999.999.999.999» и адрес «127.0.0.1». Все остальное записывается в IpLog. С MAC-адресом немного сложнее. Дело в том, что метод getHardwareAddres возвращает тип byte[] в 16-тиричной системе счисления, поэтому, прежде чем записать его в лог, приводим к «удобочетаемому» виду с помощью StringBuilder. Ну, а методы getIpLog() и getMacLog() нужны для того, чтобы вызвать их из JS и необходимым образом обработать.

P.S.: Не подписанный апплет будет возвращать только «127.0.0.1», который у нас фильтруется. Чтобы все заработало, необходимо подписать апплет. Ну и, конечно, клиент может в любой момент запретить выполнение JAVA-апплета, и ничего с этим не поделать.