mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-01-06 07:20:30 +00:00
HTTP rules now allow filtering by port
The HTTP filtering system becomes even more complex! Though in this case, it's pretty minimal, and definitely worth doing. For instance, the following rule will allow connecting to localhost on port :8080. [[http.rules]] host = "127.0.0.1" port = 8080 action = "allow" # Other rules as before. Closes #540
This commit is contained in:
parent
87393e8aef
commit
275ca58a82
@ -63,10 +63,10 @@ public final class ComputerCraft
|
||||
public static boolean httpWebsocketEnabled = true;
|
||||
public static List<AddressRule> httpRules = Collections.unmodifiableList( Stream.concat(
|
||||
Stream.of( DEFAULT_HTTP_DENY )
|
||||
.map( x -> AddressRule.parse( x, Action.DENY.toPartial() ) )
|
||||
.map( x -> AddressRule.parse( x, null, Action.DENY.toPartial() ) )
|
||||
.filter( Objects::nonNull ),
|
||||
Stream.of( DEFAULT_HTTP_ALLOW )
|
||||
.map( x -> AddressRule.parse( x, Action.ALLOW.toPartial() ) )
|
||||
.map( x -> AddressRule.parse( x, null, Action.ALLOW.toPartial() ) )
|
||||
.filter( Objects::nonNull )
|
||||
).collect( Collectors.toList() ) );
|
||||
|
||||
|
@ -24,14 +24,14 @@ public class CheckUrl extends Resource<CheckUrl>
|
||||
|
||||
private final IAPIEnvironment environment;
|
||||
private final String address;
|
||||
private final String host;
|
||||
private final URI uri;
|
||||
|
||||
public CheckUrl( ResourceGroup<CheckUrl> limiter, IAPIEnvironment environment, String address, URI uri )
|
||||
{
|
||||
super( limiter );
|
||||
this.environment = environment;
|
||||
this.address = address;
|
||||
host = uri.getHost();
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public void run()
|
||||
@ -47,8 +47,9 @@ public class CheckUrl extends Resource<CheckUrl>
|
||||
|
||||
try
|
||||
{
|
||||
InetSocketAddress netAddress = NetworkUtils.getAddress( host, 80, false );
|
||||
NetworkUtils.getOptions( host, netAddress );
|
||||
boolean ssl = uri.getScheme().equalsIgnoreCase( "https" );
|
||||
InetSocketAddress netAddress = NetworkUtils.getAddress( uri, ssl );
|
||||
NetworkUtils.getOptions( uri.getHost(), netAddress );
|
||||
|
||||
if( tryClose() ) environment.queueEvent( EVENT, address, true );
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import io.netty.handler.ssl.SslContextBuilder;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.security.KeyStore;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
@ -99,6 +100,21 @@ public final class NetworkUtils
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link InetSocketAddress} from a {@link java.net.URI}.
|
||||
*
|
||||
* Note, this may require a DNS lookup, and so should not be executed on the main CC thread.
|
||||
*
|
||||
* @param uri The URI to fetch.
|
||||
* @param ssl Whether to connect with SSL. This is used to find the default port if not otherwise specified.
|
||||
* @return The resolved address.
|
||||
* @throws HTTPRequestException If the host is not malformed.
|
||||
*/
|
||||
public static InetSocketAddress getAddress( URI uri, boolean ssl ) throws HTTPRequestException
|
||||
{
|
||||
return getAddress( uri.getHost(), uri.getPort(), ssl );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link InetSocketAddress} from the resolved {@code host} and port.
|
||||
*
|
||||
@ -128,7 +144,7 @@ public final class NetworkUtils
|
||||
*/
|
||||
public static Options getOptions( String host, InetSocketAddress address ) throws HTTPRequestException
|
||||
{
|
||||
Options options = AddressRule.apply( ComputerCraft.httpRules, host, address.getAddress() );
|
||||
Options options = AddressRule.apply( ComputerCraft.httpRules, host, address );
|
||||
if( options.action == Action.DENY ) throw new HTTPRequestException( "Domain not permitted" );
|
||||
return options;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@ -52,17 +53,23 @@ public final class AddressRule
|
||||
|
||||
private final HostRange ip;
|
||||
private final Pattern domainPattern;
|
||||
private final Integer port;
|
||||
private final PartialOptions partial;
|
||||
|
||||
private AddressRule( @Nullable HostRange ip, @Nullable Pattern domainPattern, @Nonnull PartialOptions partial )
|
||||
private AddressRule(
|
||||
@Nullable HostRange ip,
|
||||
@Nullable Pattern domainPattern,
|
||||
@Nullable Integer port,
|
||||
@Nonnull PartialOptions partial )
|
||||
{
|
||||
this.ip = ip;
|
||||
this.domainPattern = domainPattern;
|
||||
this.partial = partial;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static AddressRule parse( String filter, @Nonnull PartialOptions partial )
|
||||
public static AddressRule parse( String filter, @Nullable Integer port, @Nonnull PartialOptions partial )
|
||||
{
|
||||
int cidr = filter.indexOf( '/' );
|
||||
if( cidr >= 0 )
|
||||
@ -117,24 +124,27 @@ public final class AddressRule
|
||||
size -= 8;
|
||||
}
|
||||
|
||||
return new AddressRule( new HostRange( minBytes, maxBytes ), null, partial );
|
||||
return new AddressRule( new HostRange( minBytes, maxBytes ), null, port, partial );
|
||||
}
|
||||
else
|
||||
{
|
||||
Pattern pattern = Pattern.compile( "^\\Q" + filter.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" );
|
||||
return new AddressRule( null, pattern, partial );
|
||||
return new AddressRule( null, pattern, port, partial );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given address matches a series of patterns.
|
||||
*
|
||||
* @param domain The domain to match
|
||||
* @param address The address to check.
|
||||
* @param domain The domain to match
|
||||
* @param socketAddress The address to check.
|
||||
* @return Whether it matches any of these patterns.
|
||||
*/
|
||||
private boolean matches( String domain, InetAddress address )
|
||||
private boolean matches( String domain, InetSocketAddress socketAddress )
|
||||
{
|
||||
InetAddress address = socketAddress.getAddress();
|
||||
if( port != null && port != socketAddress.getPort() ) return false;
|
||||
|
||||
if( domainPattern != null )
|
||||
{
|
||||
if( domainPattern.matcher( domain ).matches() ) return true;
|
||||
@ -155,7 +165,7 @@ public final class AddressRule
|
||||
return ip != null && ip.contains( address );
|
||||
}
|
||||
|
||||
public static Options apply( Iterable<? extends AddressRule> rules, String domain, InetAddress address )
|
||||
public static Options apply( Iterable<? extends AddressRule> rules, String domain, InetSocketAddress address )
|
||||
{
|
||||
PartialOptions options = null;
|
||||
boolean hasMany = false;
|
||||
|
@ -49,12 +49,14 @@ public class AddressRuleConfig
|
||||
public static boolean checkRule( UnmodifiableConfig builder )
|
||||
{
|
||||
String hostObj = get( builder, "host", String.class ).orElse( null );
|
||||
Integer port = get( builder, "port", Number.class ).map( Number::intValue ).orElse( null );
|
||||
return hostObj != null && checkEnum( builder, "action", Action.class )
|
||||
&& check( builder, "port", Number.class )
|
||||
&& check( builder, "timeout", Number.class )
|
||||
&& check( builder, "max_upload", Number.class )
|
||||
&& check( builder, "max_download", Number.class )
|
||||
&& check( builder, "websocket_message", Number.class )
|
||||
&& AddressRule.parse( hostObj, PartialOptions.DEFAULT ) != null;
|
||||
&& AddressRule.parse( hostObj, port, PartialOptions.DEFAULT ) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -64,6 +66,7 @@ public class AddressRuleConfig
|
||||
if( hostObj == null ) return null;
|
||||
|
||||
Action action = getEnum( builder, "action", Action.class ).orElse( null );
|
||||
Integer port = get( builder, "port", Number.class ).map( Number::intValue ).orElse( null );
|
||||
Integer timeout = get( builder, "timeout", Number.class ).map( Number::intValue ).orElse( null );
|
||||
Long maxUpload = get( builder, "max_upload", Number.class ).map( Number::longValue ).orElse( null );
|
||||
Long maxDownload = get( builder, "max_download", Number.class ).map( Number::longValue ).orElse( null );
|
||||
@ -77,7 +80,7 @@ public class AddressRuleConfig
|
||||
websocketMessage
|
||||
);
|
||||
|
||||
return AddressRule.parse( hostObj, options );
|
||||
return AddressRule.parse( hostObj, port, options );
|
||||
}
|
||||
|
||||
private static <T> boolean check( UnmodifiableConfig config, String field, Class<T> klass )
|
||||
|
@ -136,7 +136,7 @@ public class HttpRequest extends Resource<HttpRequest>
|
||||
try
|
||||
{
|
||||
boolean ssl = uri.getScheme().equalsIgnoreCase( "https" );
|
||||
InetSocketAddress socketAddress = NetworkUtils.getAddress( uri.getHost(), uri.getPort(), ssl );
|
||||
InetSocketAddress socketAddress = NetworkUtils.getAddress( uri, ssl );
|
||||
Options options = NetworkUtils.getOptions( uri.getHost(), socketAddress );
|
||||
SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null;
|
||||
|
||||
|
@ -129,8 +129,7 @@ public class Websocket extends Resource<Websocket>
|
||||
try
|
||||
{
|
||||
boolean ssl = uri.getScheme().equalsIgnoreCase( "wss" );
|
||||
|
||||
InetSocketAddress socketAddress = NetworkUtils.getAddress( uri.getHost(), uri.getPort(), ssl );
|
||||
InetSocketAddress socketAddress = NetworkUtils.getAddress( uri, ssl );
|
||||
Options options = NetworkUtils.getOptions( uri.getHost(), socketAddress );
|
||||
SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null;
|
||||
|
||||
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
|
||||
package dan200.computercraft.core.apis.http.options;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class AddressRuleTest
|
||||
{
|
||||
@Test
|
||||
public void matchesPort()
|
||||
{
|
||||
Iterable<AddressRule> rules = Collections.singletonList( AddressRule.parse(
|
||||
"127.0.0.1", 8080,
|
||||
new PartialOptions( Action.ALLOW, null, null, null, null )
|
||||
) );
|
||||
|
||||
assertEquals( apply( rules, "localhost", 8080 ).action, Action.ALLOW );
|
||||
assertEquals( apply( rules, "localhost", 8081 ).action, Action.DENY );
|
||||
}
|
||||
|
||||
private Options apply( Iterable<AddressRule> rules, String host, int port )
|
||||
{
|
||||
return AddressRule.apply( rules, host, new InetSocketAddress( host, port ) );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user