Zadanie na 17.01.2016 z SKJ.
Niestety nie mam gotowego rozwiązania, ale mam serwer proxy z filtrem po IP (z maską sieci) i domenie, więc zostało dopisać protokół do ustawiania różnych ograniczeń zgodnie z treścią zadania.
Aby z niego skorzystać należy zainstalować 'Maven’ w Eclipse. W moim 'Eclipse for Java’ był już dołączony, a w necie jest dużo kursów jak to zrobić. Aby sprawdzić czy jest zainstalowany wejdź w 'Window -> Preferences’, po lewej stronie powinien być 'Maven’ na liście . Po instalacji Mavena trzeba załadować listę bibliotek:
Kliknij na górze Eclipse: 'Window -> Show View -> Other..’, a w otwartym oknie w 'Maven -> Maven Repositories’. Na dole Eclipse otworzy się nowe okno. Rozwinąć opcję 'Global’ i nacisnij prawym myszki na 'centel’. W menu kliknij 'Rebuild Index’. Może to zająć kilka-kilkanaście minut.
Kolejne kroki konfiguracji to dużo pisania. Mam nadzieję, że projekt Maven który eksportowałem jako archiwum z Eclipse wam zadziała:
http://skalski.at/files/files/PJWSTK/SKJ_proxy_filters/LittleProxyWithIpAndDomainFilters.zip
Program składa się z LittleProxy-1.1.0-beta1 (to coś powinien wam zainstalować Maven automatycznie jak wgracie mój projekt, bo jest w nim plik 'pom.xml’ w którym jest takie 'dependency’) oraz tylko 2 plików:
MyProxyApp.java (z mainem):
package prx2.prx2;
import org.littleshoot.proxy.HttpFiltersAdapter;
import org.littleshoot.proxy.HttpFiltersSourceAdapter;
import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.HttpRequest;
public class MyProxyApp
{
public static void main( String[] args )
{
System.out.println( "Proxy started!" );
DefaultHttpProxyServer.bootstrap()
.withPort(8088)
.withFiltersSource(new HttpFiltersSourceAdapter()
{
public HttpFiltersAdapter filterRequest(HttpRequest originalRequest, ChannelHandlerContext ctx)
{
return new MyHttpFilter(originalRequest, ctx);
}
})
.start();
System.out.println( "Proxy is working!" );
/*
* TUTAJ KOD ODPOWIEDZIALNY ZA KOMUNIKACJE Z KLIENTEM KONTROLUJACYM LISTY DOSTEPU
* postawienie jakiegos serwera, na jakims porcie, nasluchiwanie polaczen, obsluga ich w nowych watkach itd.
*/
}
}
oraz pliku MyHttpFilter.java odpowiedzialnego za filtrowanie połączeń:
package prx2.prx2;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.littleshoot.proxy.HttpFiltersAdapter;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
public class MyHttpFilter extends HttpFiltersAdapter
{
ChannelHandlerContext ctx;
public MyHttpFilter(HttpRequest originalRequest, ChannelHandlerContext ctx)
{
super(originalRequest, ctx);
this.ctx = ctx;
}
public HttpResponse clientToProxyRequest(HttpObject httpObject)
{
if(httpObject instanceof HttpRequest)
{
HttpRequest httpRequest = (HttpRequest) httpObject;
try
{
// cos jak: http://www.onet.pl/podstrona/index.html
// LUB w przypadku HTTPS: www.onet.pl:443
String uri = httpRequest.getUri();
// nalezy z 'uri' wyciagnac 'www.onet.pl'
String[] domainData = uri.split("/", 4);
String domain = null;
if(domainData.length == 1)
{
domain = domainData[0].split(":")[0];
}
else if(domainData.length >= 3)
{
domain = domainData[2].split(":")[0];
}
else
{
throw new Exception("INVALID HOST FORMAT");
}
// IP otwierajacego strone www w formacie: 127.0.0.1
String clientIP = ctx.channel().remoteAddress().toString().split(":")[0].split("/")[1];
// IP w formacie ulatwiajacym porownywanie przy uzyciu maski
int clientIPint = MyHttpFilter.ipStringToInt(clientIP);
boolean blockWebsite = false;
// KOD REGULUJACY DOSTEP DO DANEJ STRONY
// PRZYKLADOWE BLOKADY
if(domain.contains("google")) // dostepne: contains, equals [nie porownywac uzywajac '==', to nie C++!], startsWith, endsWith
blockWebsite = true;
if(domain.equals("www.wp.pl") || domain.equals("wp.pl")) // mozna zamiast tego 'endsWith'
blockWebsite = true;
if(isIpInNetwork(clientIPint, MyHttpFilter.ipStringToInt("127.0.2.2"), 24)) // czy klient w sieci: 127.0.2.2/24 (znaczy 127.0.2.*)
blockWebsite = true;
// JESLI ZABLOKOWANY, TO NIE WYSYLAJ ZAPYTANIA DO WSKAZANEGO SERWERA, TYLKO OD RAZU ZWROC KLIENTOWI KOD 403
if(blockWebsite)
{
System.out.println("ACCESS DENIED FOR CLIENT IP: " + clientIP + " (" + clientIPint + "), DOMAIN: " + domain);
return new DefaultFullHttpResponse(httpRequest.getProtocolVersion(), HttpResponseStatus.FORBIDDEN, Unpooled.copiedBuffer("403 PROXY: ACCESS DENIED".getBytes()));
}
System.out.println("ACCESS GRANTED FOR CLIENT IP: " + clientIP + " (" + clientIPint + "), DOMAIN: " + domain);
}
catch (Exception e)
{
// jesli wystapil blad przy zamianie IP (stringa np. "127.0.0.0") na ciag bajtow, to zwroc blad 500
return new DefaultFullHttpResponse(httpRequest.getProtocolVersion(), HttpResponseStatus.INTERNAL_SERVER_ERROR, Unpooled.copiedBuffer(("500 PROXY: " + e.getMessage()).getBytes()));
}
}
return null;
}
public static int ipStringToInt(String ipString) throws Exception
{
Inet4Address ipv4;
try
{
ipv4 = (Inet4Address) InetAddress.getByName(ipString);
}
catch (UnknownHostException e)
{
throw new Exception("CANNOT RESOLVE ADDRESS " + ipString);
}
byte[] ipAsByteArray = ipv4.getAddress();
int ipAsInt = ((ipAsByteArray[0] & 0xFF) << 24) |
((ipAsByteArray[1] & 0xFF) << 16) |
((ipAsByteArray[2] & 0xFF) << 8) |
((ipAsByteArray[3] & 0xFF) << 0);
return ipAsInt;
}
public static boolean isIpInNetwork(int testIp, int networkIp, int networkMask) throws Exception
{
// magia na bitach (operacja AND na bitach IP i bitach maski)
int maskInt = ~((1 << (32 - networkMask)) - 1);
return ((testIp & maskInt) == (networkIp & maskInt));
}
}
Jako przykład dodałem do filtra 3 reguły:
// dostepne: contains, equals [nie porownywac uzywajac '==', to nie C++!], startsWith, endsWith
if(domain.contains("google"))
blockWebsite = true;
// mozna zamiast tego 'endsWith'
if(domain.equals("www.wp.pl") || domain.equals("wp.pl"))
blockWebsite = true;
// czy klient w sieci: 127.0.2.2/24 (znaczy 127.0.2.*)
if(isIpInNetwork(clientIPint, MyHttpFilter.ipStringToInt("127.0.2.2"), 24))
blockWebsite = true;
Wasze zadanie to zrobić protokół komunikacji na jakimś innym porcie, przez który użytkownik będzie mógł dodawać listy IP i listy domen, a potem wiązać je dodając zasadę 'allow’ czy 'deny’.
Następnie trzeba tylko dopisać, żeby te listy były uwzględniane przez proxy i opisać wszystko dokładnie w dokumentacji.
Zgodnie z poleceniem, serwer proxy można ściągnąć z sieci i nie trzeba wiedzieć jak on działa.