Alguém sabe um componente Java para verificar se o endereço IP é de especial rede / máscara? [fechadas]

StackOverflow https://stackoverflow.com/questions/577363

  •  05-09-2019
  •  | 
  •  

Pergunta

Eu preciso determinar se determinado endereço IP é de alguma rede especial i deve autenticar automaticamente.

Foi útil?

Solução

Apache Commons Net tem org.apache.commons.net.util.SubnetUtils que aparece para satisfazer as suas necessidades. Parece que você fazer algo como isto:

SubnetInfo subnet = (new SubnetUtils("10.10.10.0", "255.255.255.128")).getInfo();
boolean test = subnet.isInRange("10.10.10.10");

Note, como Carson ressalta, que o Apache Commons Net tem um bug que o impede de dar a resposta correta em alguns casos. Carson sugere usando a versão SVN para evitar este erro.

Outras dicas

Opção 1:

Use spring-security-web 's IpAddressMatcher . Ao contrário Apache Commons Net, ele suporta tanto IPv4 e IPv6.

import org.springframework.security.web.util.matcher.IpAddressMatcher;
...

private void checkIpMatch() {
    matches("192.168.2.1", "192.168.2.1"); // true
    matches("192.168.2.1", "192.168.2.0/32"); // false
    matches("192.168.2.5", "192.168.2.0/24"); // true
    matches("92.168.2.1", "fe80:0:0:0:0:0:c0a8:1/120"); // false
    matches("fe80:0:0:0:0:0:c0a8:11", "fe80:0:0:0:0:0:c0a8:1/120"); // true
    matches("fe80:0:0:0:0:0:c0a8:11", "fe80:0:0:0:0:0:c0a8:1/128"); // false
    matches("fe80:0:0:0:0:0:c0a8:11", "192.168.2.0/32"); // false
}

private boolean matches(String ip, String subnet) {
    IpAddressMatcher ipAddressMatcher = new IpAddressMatcher(subnet);
    return ipAddressMatcher.matches(ip);
}

Opção 2 (uma solução leve!):

O código na parte anterior funciona perfeitamente bem , mas ele precisa spring-security-web para ser incluído.

Se você não está disposto a incluir framework Spring no seu projeto, você pode usar essa classe que é uma versão ligeiramente modificada do classe original a partir da Primavera, para que ele não tem não dependências -JDK.

/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * Matches a request based on IP Address or subnet mask matching against the remote
 * address.
 * <p>
 * Both IPv6 and IPv4 addresses are supported, but a matcher which is configured with an
 * IPv4 address will never match a request which returns an IPv6 address, and vice-versa.
 *
 * @author Luke Taylor
 * @since 3.0.2
 * 
 * Slightly modified by omidzk to have zero dependency to any frameworks other than the JDK.
 */
public final class IpAddressMatcher {
    private final int nMaskBits;
    private final InetAddress requiredAddress;

    /**
     * Takes a specific IP address or a range specified using the IP/Netmask (e.g.
     * 192.168.1.0/24 or 202.24.0.0/14).
     *
     * @param ipAddress the address or range of addresses from which the request must
     * come.
     */
    public IpAddressMatcher(String ipAddress) {

        if (ipAddress.indexOf('/') > 0) {
            String[] addressAndMask = ipAddress.split("/");
            ipAddress = addressAndMask[0];
            nMaskBits = Integer.parseInt(addressAndMask[1]);
        }
        else {
            nMaskBits = -1;
        }
        requiredAddress = parseAddress(ipAddress);
        assert  (requiredAddress.getAddress().length * 8 >= nMaskBits) :
                String.format("IP address %s is too short for bitmask of length %d",
                        ipAddress, nMaskBits);
    }

    public boolean matches(String address) {
        InetAddress remoteAddress = parseAddress(address);

        if (!requiredAddress.getClass().equals(remoteAddress.getClass())) {
            return false;
        }

        if (nMaskBits < 0) {
            return remoteAddress.equals(requiredAddress);
        }

        byte[] remAddr = remoteAddress.getAddress();
        byte[] reqAddr = requiredAddress.getAddress();

        int nMaskFullBytes = nMaskBits / 8;
        byte finalByte = (byte) (0xFF00 >> (nMaskBits & 0x07));

        // System.out.println("Mask is " + new sun.misc.HexDumpEncoder().encode(mask));

        for (int i = 0; i < nMaskFullBytes; i++) {
            if (remAddr[i] != reqAddr[i]) {
                return false;
            }
        }

        if (finalByte != 0) {
            return (remAddr[nMaskFullBytes] & finalByte) == (reqAddr[nMaskFullBytes] & finalByte);
        }

        return true;
    }

    private InetAddress parseAddress(String address) {
        try {
            return InetAddress.getByName(address);
        }
        catch (UnknownHostException e) {
            throw new IllegalArgumentException("Failed to parse address" + address, e);
        }
    }
}

Diff:

+ * 
+ * Slightly modified by omidzk to have zero dependency to any frameworks other than the JDK.

-import javax.servlet.http.HttpServletRequest;
-
-import org.springframework.security.web.util.matcher.RequestMatcher;
-import org.springframework.util.StringUtils;
-import org.springframework.util.Assert;

-public final class IpAddressMatcher implements RequestMatcher {
+public final class IpAddressMatcher {

-           String[] addressAndMask = StringUtils.split(ipAddress, "/");
+           String[] addressAndMask = ipAddress.split("/");

-       Assert.isTrue(requiredAddress.getAddress().length * 8 >= nMaskBits,
+       assert  (requiredAddress.getAddress().length * 8 >= nMaskBits) :

-                       ipAddress, nMaskBits));
+                       ipAddress, nMaskBits);

-
-   public boolean matches(HttpServletRequest request) {
-       return matches(request.getRemoteAddr());
-   }

AVISO : Observe que para usar esta opção, é sua a responsabilidade de examinar cuidadosamente o licença para certificar-se usando esse código, você não está em violação de quaisquer termos mandatados pela licença acima mencionada. (É claro que a publicação deste código para Stackoverflow.com por mim não é uma violação.)

Você também pode tentar

boolean inSubnet = (ip & netmask) == (subnet & netmask);

ou menos

boolean inSubnet = (ip ^ subnet) & netmask == 0;

O open-source IPAddress Java biblioteca vai fazer isso de uma forma polimórfica para IPv4 e IPv6 e alças sub-redes. Disclaimer:. Eu sou o gerente de projeto de que a biblioteca

código Exemplo:

contains("10.10.20.0/30", "10.10.20.3");
contains("10.10.20.0/30", "10.10.20.5");
contains("1::/64", "1::1");
contains("1::/64", "2::1");
contains("1::3-4:5-6", "1::4:5");       
contains("1-2::/64", "2::");
contains("bla", "foo");

static void contains(String network, String address) {
    IPAddressString one = new IPAddressString(network);
    IPAddressString two = new IPAddressString(address);
    System.out.println(one +  " contains " + two + " " + one.contains(two));
}

Output:

10.10.20.0/30 contains 10.10.20.3 true
10.10.20.0/30 contains 10.10.20.5 false
1::/64 contains 1::1 true
1::/64 contains 2::1 false
1::3-4:5-6 contains 1::4:5 true
1-2::/64 contains 2:: true
bla contains foo false

Para verificar um IP em uma sub-rede, eu usei método isInRange na classe SubnetUtils. Mas este método tem um bug que, se sua sub-rede foi X, cada endereço IP que menor do que X, isInRange retornar true. Por exemplo, se sua sub-rede foi 10.10.30.0/24 e quiser verificar 10.10.20.5, este método retornar verdadeiro. Para lidar com este bug eu usei o código abaixo.

public static void main(String[] args){
    String list = "10.10.20.0/24";
    String IP1 = "10.10.20.5";
    String IP2 = "10.10.30.5";
    SubnetUtils  subnet = new SubnetUtils(list);
    SubnetUtils.SubnetInfo subnetInfo = subnet.getInfo();
    if(MyisInRange(subnetInfo , IP1) == true)
       System.out.println("True");
    else 
       System.out.println("False");
    if(MyisInRange(subnetInfo , IP2) == true)
       System.out.println("True");
    else
       System.out.println("False");
}

private boolean MyisInRange(SubnetUtils.SubnetInfo info, String Addr )
{
    int address = info.asInteger( Addr );
    int low = info.asInteger( info.getLowAddress() );
    int high = info.asInteger( info.getHighAddress() );
    return low <= address && address <= high;
}

aqui é uma versão que funciona com IPv4 e IPv6 um com prefixo e um com máscara de rede.

/**
 * Check if IP is within an Subnet defined by Network Address and Network Mask
 * @param  ip
 * @param  net
 * @param  mask
 * @return
 */
public static final boolean isIpInSubnet(final String ip, final String net, final int prefix) {
    try {
        final byte[] ipBin   = java.net.InetAddress.getByName(ip  ).getAddress();
        final byte[] netBin  = java.net.InetAddress.getByName(net ).getAddress();
        if(ipBin.length  != netBin.length ) return false;
        int p = prefix;
        int i = 0;
        while(p>=8) { if(ipBin[i] != netBin[i] ) return false; ++i; p-=8; }
        final int m = (65280 >> p) & 255;
        if((ipBin[i] & m) != (netBin[i]&m) ) return false;

        return true;
    } catch(final Throwable t) {
        return false;
    }
}

/**
 * Check if IP is within an Subnet defined by Network Address and Network Mask
 * @param  ip
 * @param  net
 * @param  mask
 * @return
 */
public static final boolean isIpInSubnet(final String ip, final String net, final String mask) {
    try {
        final byte[] ipBin   = java.net.InetAddress.getByName(ip  ).getAddress();
        final byte[] netBin  = java.net.InetAddress.getByName(net ).getAddress();
        final byte[] maskBin = java.net.InetAddress.getByName(mask).getAddress();
        if(ipBin.length  != netBin.length ) return false;
        if(netBin.length != maskBin.length) return false;
        for(int i = 0; i < ipBin.length; ++i) if((ipBin[i] & maskBin[i]) != (netBin[i] & maskBin[i])) return false;
        return true;
    } catch(final Throwable t) {
        return false;
    }
}

Eu sei que isso é questão muito antiga, mas me deparei com isso quando eu estava olhando para resolver o mesmo problema.

biblioteca commons-ip-matemática que eu acredito que faz um bom trabalho. Por favor, note que a partir de maio 2019, não houve nenhuma atualização para a biblioteca (Pode ser que a sua já muito madura biblioteca). Seu disponível em maven-Central

Ele suporta trabalhar com ambos os endereços IPv4 e IPv6. Sua documentação breve tem exemplos de como você pode verificar se um endereço está em um intervalo específico para IPv4 e IPv6

Exemplo para IPv4 verificação de intervalo:

        String input1 = "192.168.1.0";
        Ipv4 ipv41 = Ipv4.parse(input1);

        // Using CIDR notation to specify the networkID and netmask
        Ipv4Range range = Ipv4Range.parse("192.168.0.0/24");
        boolean result = range.contains(ipv41);
        System.out.println(result); //false

        String input2 = "192.168.0.251";
        Ipv4 ipv42 = Ipv4.parse(input2);

        // Specifying the range with a start and end.
        Ipv4 start = Ipv4.of("192.168.0.0");
        Ipv4 end = Ipv4.of("192.168.0.255");
        range = Ipv4Range.from(start).to(end);

        result = range.contains(ipv42); //true
        System.out.println(result);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top