前几天一个同事突然问我如何安装和配置iptables转发规则。沟通后发现他生产环境用的iptables,测试环境用的squid。我当时询问他,代理服务器发生变化了,代码不需要跟着调整吗。他说java代码不用改动,说之前已经这样做过一次。我感到很好奇,软件变化,代码居然不用调整,一直想不通,索性今天在自己电脑写个代码java利用iptables、squid访问nginx的demo,发现确实是这样。但是也可能不一样。测试分析记录如下:

一、环境配置

  • 服务器1:192.168.182.129   安装iptables、squid。其中iptables配转发规则:所有到iptables 8080的tcp网络请求都网路地址转换为192.168.182.130:8080。配置如下
  • service  iptables  restart
    echo 1 > /proc/sys/net/ipv4/ip_forward
    
    iptables -F
    iptables -t nat -F
    
    
    iptables -t nat -A PREROUTING -p tcp -d 192.168.182.129 --dport 8080 -j DNAT --t              o-destination 192.168.182.130:8080
    
    iptables -t nat -A POSTROUTING -p tcp --destination 192.168.182.130 --dport 8080             -j MASQUERADE
    

squid增加8080端口开通。配置如下

  • 服务器2:192.168.182.130  仅安装nginx。启动8080端口,并配置仅服务器1可访问nginx。这样此台服务器仅能通过代理服务器1进行访问。

二、测试java通过squid访问nginx

  测试条件:、

 服务器2:./sbin/nginx,启动nginx.

服务器1:systemctl stop iptables.service、systemctl start squid.service。启动squid且不启动iptables 。

java代码使用通过squid代理访问nginx服务器,代码样例如下:

package org.example;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;

public class ProxyHttpClient {
    public static void main(String[] args) {
        try {
            // 创建代理服务器配置
            Proxy proxy = new Proxy(Proxy.Type.HTTP,
                    new InetSocketAddress("192.168.182.129", 3128));

            // 创建URL对象
            URL url = new URL("http://192.168.182.130:8080/index.html");

            // 打开连接并设置代理
            HttpURLConnection connection = (HttpURLConnection) url.openConnection(proxy);

            // 设置请求方法
            connection.setRequestMethod("GET");

            // 添加请求头(如果需要)
            connection.setRequestProperty("User-Agent", "Mozilla/5.0");

            // 获取响应码
            int responseCode = connection.getResponseCode();
            System.out.println("HTTP Response Code: " + responseCode);

            // 读取响应内容
            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(connection.getInputStream()));
            String line;
            StringBuilder response = new StringBuilder();

            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            reader.close();

            // 输出响应
            System.out.println("Response Body: " + response.toString());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  其中// 创建代理服务器配置 Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("192.168.182.129", 3128));这里的ip为squid服务器地址和端口。

// 创建URL对象
URL url = new URL("http://192.168.182.130:8080/index.html");为真正的请求的url地址,这里的地址为真正需要访问的地址或域名。

测试结果:java代码正常访问了nginx,并返回了响应信息。<!DOCTYPE html><html><h1>Welcome to nginx!-182.130</h1></html>

三、测试java通过iptables访问nginx

  测试条件:

服务器1: systemctl stop squid.service停止squid进程并启动iptables并配置规则 。

java代码使用通过iptables代理访问nginx服务器,代码样例如下:

package org.example;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;

public class ProxyHttpClient {
    public static void main(String[] args) {
        try {
            // 创建代理服务器配置
            Proxy proxy = new Proxy(Proxy.Type.HTTP,
                    new InetSocketAddress("192.168.182.129", 8080));

            // 创建URL对象
            URL url = new URL("http://192.168.182.130:8080/index.html");

            // 打开连接并设置代理
            HttpURLConnection connection = (HttpURLConnection) url.openConnection(proxy);

            // 设置请求方法
            connection.setRequestMethod("GET");

            // 添加请求头(如果需要)
            connection.setRequestProperty("User-Agent", "Mozilla/5.0");

            // 获取响应码
            int responseCode = connection.getResponseCode();
            System.out.println("HTTP Response Code: " + responseCode);

            // 读取响应内容
            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(connection.getInputStream()));
            String line;
            StringBuilder response = new StringBuilder();

            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            reader.close();

            // 输出响应
            System.out.println("Response Body: " + response.toString());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
/ 创建代理服务器配置
Proxy proxy = new Proxy(Proxy.Type.HTTP,new InetSocketAddress("192.168.182.129", 8080));其中这里为iptables的地址和端口。
// 创建URL对象
URL url = new URL("http://192.168.182.130:8080/index.html");为真正的请求的url地址,这里的地址为真正需要访问的地址或域名。

测试结果:java代码正常访问了nginx,并返回了响应信息。<!DOCTYPE html><html><h1>Welcome to nginx!-182.130</h1></html>

测试结论:squid的代码确实可以适用于iptables,仅仅调整如下的代理机的ip和端口。

Proxy proxy = new Proxy(Proxy.Type.HTTP,new InetSocketAddress("192.168.182.129", 8080));

思考:

iptables作为透明代理,工作在网络层和传输层。squid工作在应用层。iptables对客户端是无感知,这意味着客户端完全可以直接访问iptables,而无需知道真实目的地址。这样java代码里其实无需利用代理,可以直接访问iptables。代码如下:

package org.example;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.ProxyAuthenticationStrategy;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
import org.apache.http.util.EntityUtils;
import java.net.URI;
import java.net.URISyntaxException;

public class ApacheHttpClientWithProxy {
    public static void main(String[] args) {
        try {
            // 创建代理服务器配置
            org.apache.http.HttpHost proxy = new org.apache.http.HttpHost(
                    "192.168.182.129", 8080, "http");

            // 创建带有代理设置的 HttpClient
            DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
            HttpClient httpClient = HttpClients.custom()
                    .setRoutePlanner(routePlanner)
                    .setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy())
                    .build();

            // 创建 HTTP 请求
            HttpGet request = new HttpGet();
            request.setURI(new URI("http://192.168.182.130:8080"));

            // 执行请求
            HttpResponse response = httpClient.execute(request);

            // 处理响应
            System.out.println("Status Code: " + response.getStatusLine().getStatusCode());
            System.out.println("Response Body: " +
                    EntityUtils.toString(response.getEntity()));

        } catch (URISyntaxException | java.io.IOException e) {
            e.printStackTrace();
        }
    }
}

这里不再需要代理服务器类的实例Proxy,也不需要知道真实目的地址。仅仅把iptables作为真实服务器访问。

// 创建代理服务器配置
org.apache.http.HttpHost proxy = new org.apache.http.HttpHost(
        "192.168.182.129", 8080, "http");

测试结果:下图是结果,也是可以正常访问。验证了iptables是透明转发,客户端无需知道真实服务器的信息。

综上,对于http协议,使用squid的java代码可以适用于iptables机器,但使用iptables的java代码不一定适用于squid。

按iptables的透明传输作用看,理论上使用iptables的java代码也不应该出现代理类对象new Proxy。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐