Проверка IP-подсети в JSP - PullRequest
2 голосов
/ 07 октября 2008

У меня есть следующий код JSP, который защищает мою веб-страницу и отображает ее только для того, чтобы узнать IP

String ip_h = request.getRemoteAddr();  
String host_h = request.getRemoteHost();  
String iplist[] = new String[1];  
iplist[0] = "127.0.0.1";  
iplist[1] = "10.217.106.248";  

int count = iplist.length;  
boolean flag = false;  
int zz = 0;  
//return;
System.out.println(host_h);  
while ( (flag==false) && ( zz < count) )  
{  
   if (ip_h.equals(iplist[zz]) || host_h.equals(iplist[zz]) )  
   {  
      flag = true;  
   }  
   zz++;  
}

Однако я бы предпочел проверить диапазоны подсетей, т. Е. Разрешены все пользователи, принадлежащие 10.217.0.0/16.

Как мне это сделать?

Ответы [ 5 ]

2 голосов
/ 07 октября 2008

Не стесняйтесь использовать этот класс IpRangeFilter. См. Комментарий класса для объяснения.

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.collections15.Predicate;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

/**
 * I am a filter used to determine if a given IP Address is covered by the IP range specified in 
 * the constructor.  I accept IP ranges in the form of full single IP addresses, e.g. 10.1.0.23
 * or network/netmask pairs in CIDR format e.g. 10.1.0.0/16
 */
public class IpRangeFilter implements Predicate<InetAddress> {

    private final long network;
    private final long netmask;

    private final String ipRange;

    private static final Pattern PATTERN = Pattern.compile("((?:\\d|\\.)+)(?:/(\\d{1,2}))?");

    public IpRangeFilter(String ipRange) throws UnknownHostException {
        Matcher matcher = PATTERN.matcher(ipRange);
        if (matcher.matches()) {
            String networkPart = matcher.group(1);
            String cidrPart = matcher.group(2);

            long netmask = 0;
            int cidr = cidrPart == null ? 32 : Integer.parseInt(cidrPart);
            for (int pos = 0; pos < 32; ++pos) {
                if (pos >= 32-cidr) {
                    netmask |= (1L << pos);
                }
            }

            this.network = netmask & toMask(InetAddress.getByName(networkPart));
            this.netmask = netmask;
            this.ipRange = ipRange;

        } else {
            throw new IllegalArgumentException("Not a valid IP range: " + ipRange);
        }
    }

    public String getIpRange() {
        return ipRange;
    }

    public boolean evaluate(InetAddress address) {
        return isInRange(address);
    }

    public boolean isInRange(InetAddress address) {
        return network == (toMask(address) & netmask);
    }

    /**
     * Convert the bytes in the InetAddress into a bit mask stored as a long.
     * We could use int's here, but java represents those in as signed numbers, which can be a pain 
     * when debugging.
     * @see http://www.captain.at/howto-java-convert-binary-data.php
     */
    static long toMask(InetAddress address) {
        byte[] data = address.getAddress();
        long accum = 0;
        int idx = 3;
        for ( int shiftBy = 0; shiftBy < 32; shiftBy += 8 ) {
            accum |= ( (long)( data[idx] & 0xff ) ) << shiftBy;
            idx--;
        }
        return accum;
    }
}
2 голосов
/ 07 октября 2008

Не лучше ли использовать сервер приложений для блокировки диапазона IP-адресов? В apache вы можете создать псевдоним для каталога, поместить свой код в каталог, а затем в директиве псевдонима разрешить только определенные IP или диапазоны:

Псевдоним / mydir "/ usr / local / mydir"

приказ отказать, разрешить отрицать все Разрешить с 10.217.106.248 Разрешить с 127.0.0.1 разрешить с 10.217.106 # это диапазон

таким образом, вам не нужно кодировать такого рода "магическое число"

Я уверен, что вы можете делать такие вещи на других веб-серверах

2 голосов
/ 07 октября 2008

IP-адреса (по крайней мере, IPv4-адреса) действительно предназначены для представления в виде 32-разрядных целых чисел. Если вы сначала преобразуете IP-адрес в целое число, проверка диапазонов подсети становится относительно простой задачей проверки (в вашем примере), соответствуют ли первые 16 бит первым 16 битам диапазона.

0 голосов
/ 07 октября 2008

Вы можете использовать следующий фрагмент кода, конечно, он предполагает, что входные данные верны, поэтому он требует некоторого украшения (на всякий случай)

public class IPUtil
{

    private static int[] split(String ip)
    {
        int[] result = new int[4];
        StringTokenizer st = new StringTokenizer(ip, ".");
        for (int i = 0; i < 4; i++)
        {
            result[i] = Integer.parseInt(st.nextToken());
        }
        return result;
    }

    public static boolean matches(String visitorIpString, String ipString, String maskString)
    {
        int[] vip = split(visitorIpString);
        int[] ip = split(ipString);
        int[] mask = split(maskString);

        for (int i = 0; i < 4; i++)
        {
            if ((vip[i] & mask[i]) != ip[i])
            {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args)
    {

        String ip = "192.168.12.0";
        String mask = "255.255.255.0";
        String visitorIP = "192.168.12.55";

        System.out.println(matches(visitorIP, ip, mask));
    }
}
0 голосов
/ 07 октября 2008

Попробуйте Subnet класс из этого сообщения об ошибке .

...