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.