Qualcuno sa un componente Java per verificare se l'indirizzo IP è da particolare rete / maschera di rete? [chiuso]

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

  •  05-09-2019
  •  | 
  •  

Domanda

Ho bisogno di determinare se dato indirizzo IP è da qualche rete speciale che deve autenticare automaticamente.

È stato utile?

Soluzione

Apache Commons Net ha org.apache.commons.net.util.SubnetUtils che sembra soddisfare le vostre esigenze. Sembra che si fa qualcosa di simile a questo:

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

Si noti, come Carson sottolinea che Apache Commons Net ha un bug che impedisce di dare la risposta corretta in alcuni casi. Carson suggerisce di utilizzare la versione SVN per evitare questo bug.

Altri suggerimenti

Opzione 1:

spring-security-web 's IpAddressMatcher . A differenza di Apache Commons Net, supporta sia IPv4 che 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);
}

Opzione 2 (una soluzione leggera!):

Il codice nella parte precedente funziona perfettamente bene , ma ha bisogno spring-security-web da inserire.

Se non si è disposti a includere framework Spring nel progetto, è possibile utilizzare questa classe, che è una versione leggermente modificata del class originale a partire dalla primavera, in modo che non ha non dipendenze -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());
-   }

ATTENZIONE : Si noti che per l'utilizzo di questa opzione, è vostra responsabilità di esaminare attentamente la licenza per assicurarsi che utilizzando questo codice, non si è in violazione di qualsiasi termine di mandato dalla licenza di cui sopra. (Naturalmente la pubblicazione di questo codice per Stackoverflow.com da me non è una violazione.)

Si può anche provare

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

o meno

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

L'open-source IPAddress Libreria Java farà questo in modo polimorfico sia per IPv4 che IPv6 e gestisce le sottoreti. Disclaimer: io sono il responsabile del progetto di quella biblioteca

.

Esempio di codice:

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

Per controllare un IP in una sottorete, ho usato il metodo isInRange in classe SubnetUtils. Ma questo metodo ha un bug che se la vostra sottorete fosse X, ogni indirizzo IP che inferiore a X, isInRange tornare vero. Per esempio se la vostra sottorete era 10.10.30.0/24 e si desidera controllare 10.10.20.5, questo metodo restituisca true. Per far fronte a questo problema ho usato sotto il codice.

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;
}

qui è una versione che funziona con IPv4 e IPv6 uno con prefisso e uno con la maschera di rete.

/**
 * 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;
    }
}

So che questo è molto vecchia questione, ma mi sono imbattuto su questo quando stavo cercando di risolvere lo stesso problema.

C'è commons-ip-math libreria che ritengo fa un ottimo lavoro. Si prega di notare che a partire da maggio 2019, non v'è stato alcun aggiornamento alla libreria (potrebbe essere che la sua biblioteca già molto maturo). La sua disponibili sul Maven centro-

Supporta lavorare sia con IPv4 e indirizzi IPv6. La loro breve documentazione ha esempi su come si può verificare se un indirizzo è in una gamma specifica per IPv4 e IPv6

Esempio per IPv4 controllo gamma:

        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);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top