Java Netty框架自建DNS代理服务器教程(java的netty框架)

  本篇文章为你整理了Java Netty框架自建DNS代理服务器教程(java的netty框架)的详细内容,包含有netty搭建 java的netty框架 netty创建服务端 java dns server Java Netty框架自建DNS代理服务器教程,希望能帮助你了解 Java Netty框架自建DNS代理服务器教程。

  DNS协议作为着互联网客户端-服务器通信模式得第一关,在当下每天都有成千上亿上网记录产生得当今社会,其重要性自然不可言喻。在国内比较有名得DNS服务器有电信得114.114.114.114、阿里云得223.5.5.5,DNSPod得119.29.29.29,配置一个好的DNS服务器可以缩短请求响应时间、降低DNS劫持概率,提升上网体验。

  上面这些都是互联网公用DNS服务器,本文博主教大家使用 Java Netty 自建DNS代理服务器,目前网上对于使用Netty自建DNS服务器得教程良莠不齐,大多没有代理步骤,达不到博主想要得代理效果,因而创建此文。觉得本文有帮助得可以关注博主github

  https://github.com/wayn111

  一、自建DNS代理服务器有哪些优势

  域名控制:对于特定域名可以自由控制访问权限(屏蔽对特定网站访问)

  域名记录:记录局域网内各个主机得域名访问(记录员工上网记录)

  配置内网域名:通过自建DNS服务器可以配置内网域名,节约成本

  DNS负载均衡:通过自建DNS服务器可以轻松实现对于访问域名得负载均衡配置

  二、自建DNS代理服务器代码

  添加域名黑名单文件,resources 文件夹下添加 black_list.txt 文件

  

google.com.

 

  facebook.com.

  

 

  初始化 BLACK_LIST_DOMAIN

  

private static final List String BLACK_LIST_DOMAIN = new ArrayList ();

 

   static {

   String s;

   try (InputStream is = DnsServer.class.getClassLoader().getResourceAsStream("black_list.txt");

   BufferedReader br = new BufferedReader(new InputStreamReader(is))) {

   while (StrUtil.isNotBlank(s = br.readLine())) {

   BLACK_LIST_DOMAIN.add(s);

   } catch (Exception e) {

   log.error(e.getMessage(), e);

  

 

  使用 UDP 协议绑定本机53端口,并初始化 ProxyUdp DNS请求代理对象

  

@Slf4j

 

  public final class DnsServer {

   private static final List String BLACK_LIST_DOMAIN = new ArrayList ();

   static {

   public static void main(String[] args) throws Exception {

   ProxyUdp proxyUdp = new ProxyUdp();

   proxyUdp.init();

   final int[] num = {0};

   final NioEventLoopGroup group = new NioEventLoopGroup();

   Bootstrap bootstrap = new Bootstrap();

   bootstrap.group(group).channel(NioDatagramChannel.class)

   .handler(new ChannelInitializer NioDatagramChannel () {

   @Override

   protected void initChannel(NioDatagramChannel nioDatagramChannel) {

   nioDatagramChannel.pipeline().addLast(...);

   }).option(ChannelOption.SO_BROADCAST, true);

   int port = 53;

   ChannelFuture future = bootstrap.bind(port).addListener(future1 - {

   log.info("server listening port:{}", port);

   future.channel().closeFuture().addListener(future1 - {

   if (future.isSuccess()) {

   log.info(future.channel().toString());

  

 

  给 nioDatagramChannel.pipeline() 添加 ChannelHandler

  

nioDatagramChannel.pipeline().addLast(new DatagramDnsQueryDecoder());

 

   nioDatagramChannel.pipeline().addLast(new SimpleChannelInboundHandler DatagramDnsQuery () {

   @Override

   protected void channelRead0(ChannelHandlerContext ctx, DatagramDnsQuery msg) {

   try {

   DefaultDnsQuestion dnsQuestion = msg.recordAt(DnsSection.QUESTION);

   String name = dnsQuestion.name();

   log.info(name + ++num[0]);

   Channel channel = ctx.channel();

   int id = msg.id();

   channel.attr(AttributeKey. DatagramDnsQuery valueOf(String.valueOf(id))).set(msg);

   if (BLACK_LIST_DOMAIN.contains(name)) {

   DnsQuestion question = msg.recordAt(DnsSection.QUESTION);

   DatagramDnsResponse dnsResponse = getDatagramDnsResponse(msg, id, question);

   channel.writeAndFlush(dnsResponse);

   return;

   proxyUdp.send(name, msg.id(), channel);

   } catch (Exception e) {

   log.error(e.getMessage(), e);

   private DatagramDnsResponse getDatagramDnsResponse(DatagramDnsQuery msg, int id, DnsQuestion question) {

   DatagramDnsResponse dnsResponse = new DatagramDnsResponse(msg.recipient(), msg.sender(), id);

   dnsResponse.addRecord(DnsSection.QUESTION, question);

   DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord(

   question.name(),

   DnsRecordType.A, 600, Unpooled.wrappedBuffer(new byte[]{(byte) 192, (byte) 168, 1, 1}));

   dnsResponse.addRecord(DnsSection.ANSWER, queryAnswer);

   return dnsResponse;

   @Override

   public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) {

   log.error(e.getMessage(), e);

   nioDatagramChannel.pipeline().addLast(new DatagramDnsResponseEncoder());

  

 

  在 new SimpleChannelInboundHandler DatagramDnsQuery () 中 解析客户端DNS查询报文, 获取访问域名信息,如果访问域名在黑名单中,则通过 getDatagramDnsResponse() 直接返回 192.168.1.1 的DNS响应报文,反之则通过 proxyUdp 对象转发DNS查询。

  ProxyUdp 作为DNS查询代理类会通过 send(String domain, int id, Channel serverChannel) 方法传入DnsServer类收到的访问域名、DNS事务ID、serverChannel。随后包装访问域名请求DNS服务器114.114.114.114,最后通过 new SimpleChannelInboundHandler DatagramDnsResponse () 将收到的DNS响应报文通过上一步传入得 serverChannel 输出到客户端。

  

@Slf4j

 

  class ProxyUdp {

   private Channel serverChannel;

   private Channel proxyChannel;

   public void init() throws InterruptedException {

   EventLoopGroup proxyGroup = new NioEventLoopGroup();

   Bootstrap b = new Bootstrap();

   b.group(proxyGroup)

   .channel(NioDatagramChannel.class)

   .handler(new ChannelInitializer DatagramChannel () {

   @Override

   protected void initChannel(DatagramChannel ch) {

   ChannelPipeline p = ch.pipeline();

   p.addLast(new DatagramDnsQueryEncoder())

   .addLast(new DatagramDnsResponseDecoder())

   .addLast(new SimpleChannelInboundHandler DatagramDnsResponse () {

   @Override

   public void channelActive(ChannelHandlerContext ctx) {

   log.info(ctx.channel().toString());

   @Override

   protected void channelRead0(ChannelHandlerContext ctx, DatagramDnsResponse msg) {

   DatagramDnsQuery dnsQuery = localChannel.attr(AttributeKey. DatagramDnsQuery valueOf(String.valueOf(msg.id()))).get();

   DnsQuestion question = msg.recordAt(DnsSection.QUESTION);

   DatagramDnsResponse dnsResponse = new DatagramDnsResponse(dnsQuery.recipient(), dnsQuery.sender(), msg.id());

   dnsResponse.addRecord(DnsSection.QUESTION, question);

   for (int i = 0, count = msg.count(DnsSection.ANSWER); i count; i++) {

   DnsRecord record = msg.recordAt(DnsSection.ANSWER, i);

   if (record.type() == DnsRecordType.A) {

   // just print the IP after query

   DnsRawRecord raw = (DnsRawRecord) record;

   DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord(

   question.name(),

   DnsRecordType.A, 600, Unpooled.wrappedBuffer(ByteBufUtil.getBytes(raw.content())));

   dnsResponse.addRecord(DnsSection.ANSWER, queryAnswer);

   serverChannel.writeAndFlush(dnsResponse);

   @Override

   public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) {

   log.error(e.getMessage(), e);

   proxyChannel = b.bind(0).sync().addListener(future1 - {

   log.info("绑定成功");

   }).channel();

   public void send(String domain, int id, Channel serverChannel) {

   this.serverChannel = serverChannel;

   DnsQuery query = new DatagramDnsQuery(null, new InetSocketAddress("114.114.114.114", 53), id).setRecord(

   DnsSection.QUESTION,

   new DefaultDnsQuestion(domain, DnsRecordType.A));

   this.proxyChannel.writeAndFlush(query);

  

 

  自建DNS服务器全部代码

  

@Slf4j

 

  public final class DnsServer {

   private static final List String BLACK_LIST_DOMAIN = new ArrayList ();

   static {

   String s;

   try (InputStream is = DnsServer.class.getClassLoader().getResourceAsStream("black_list.txt");

   BufferedReader br = new BufferedReader(new InputStreamReader(is))) {

   while (StrUtil.isNotBlank(s = br.readLine())) {

   BLACK_LIST_DOMAIN.add(s);

   } catch (Exception e) {

   log.error(e.getMessage(), e);

   public static void main(String[] args) throws Exception {

   ProxyUdp proxyUdp = new ProxyUdp();

   proxyUdp.init();

   final int[] num = {0};

   final NioEventLoopGroup group = new NioEventLoopGroup();

   Bootstrap bootstrap = new Bootstrap();

   bootstrap.group(group).channel(NioDatagramChannel.class)

   .handler(new ChannelInitializer NioDatagramChannel () {

   @Override

   protected void initChannel(NioDatagramChannel nioDatagramChannel) {

   nioDatagramChannel.pipeline().addLast(new DatagramDnsQueryDecoder());

   nioDatagramChannel.pipeline().addLast(new SimpleChannelInboundHandler DatagramDnsQuery () {

   @Override

   protected void channelRead0(ChannelHandlerContext ctx, DatagramDnsQuery msg) {

   try {

   DefaultDnsQuestion dnsQuestion = msg.recordAt(DnsSection.QUESTION);

   String name = dnsQuestion.name();

   log.info(name + ++num[0]);

   Channel channel = ctx.channel();

   int id = msg.id();

   channel.attr(AttributeKey. DatagramDnsQuery valueOf(String.valueOf(id))).set(msg);

   if (BLACK_LIST_DOMAIN.contains(name)) {

   DnsQuestion question = msg.recordAt(DnsSection.QUESTION);

   DatagramDnsResponse dnsResponse = getDatagramDnsResponse(msg, id, question);

   channel.writeAndFlush(dnsResponse);

   return;

   proxyUdp.send(name, msg.id(), channel);

   } catch (Exception e) {

   log.error(e.getMessage(), e);

   private DatagramDnsResponse getDatagramDnsResponse(DatagramDnsQuery msg, int id, DnsQuestion question) {

   DatagramDnsResponse dnsResponse = new DatagramDnsResponse(msg.recipient(), msg.sender(), id);

   dnsResponse.addRecord(DnsSection.QUESTION, question);

   // just print the IP after query

   DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord(

   question.name(),

   DnsRecordType.A, 600, Unpooled.wrappedBuffer(new byte[]{(byte) 192, (byte) 168, 1, 1}));

   dnsResponse.addRecord(DnsSection.ANSWER, queryAnswer);

   return dnsResponse;

   @Override

   public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) {

   log.error(e.getMessage(), e);

   nioDatagramChannel.pipeline().addLast(new DatagramDnsResponseEncoder());

   }).option(ChannelOption.SO_BROADCAST, true);

   int port = 553;

   ChannelFuture future = bootstrap.bind(port).addListener(future1 - {

   log.info("server listening port:{}", port);

   future.channel().closeFuture().addListener(future1 - {

   if (future.isSuccess()) {

   log.info(future.channel().toString());

  @Slf4j

  class ProxyUdp {

   private Channel localChannel;

   private Channel proxyChannel;

   public void init() throws InterruptedException {

   EventLoopGroup proxyGroup = new NioEventLoopGroup();

   Bootstrap b = new Bootstrap();

   b.group(proxyGroup)

   .channel(NioDatagramChannel.class)

   .handler(new ChannelInitializer DatagramChannel () {

   @Override

   protected void initChannel(DatagramChannel ch) {

   ChannelPipeline p = ch.pipeline();

   p.addLast(new DatagramDnsQueryEncoder())

   .addLast(new DatagramDnsResponseDecoder())

   .addLast(new SimpleChannelInboundHandler DatagramDnsResponse () {

   @Override

   public void channelActive(ChannelHandlerContext ctx) {

   log.info(ctx.channel().toString());

   @Override

   protected void channelRead0(ChannelHandlerContext ctx, DatagramDnsResponse msg) {

   DatagramDnsQuery dnsQuery = localChannel.attr(AttributeKey. DatagramDnsQuery valueOf(String.valueOf(msg.id()))).get();

   DnsQuestion question = msg.recordAt(DnsSection.QUESTION);

   DatagramDnsResponse dnsResponse = new DatagramDnsResponse(dnsQuery.recipient(), dnsQuery.sender(), msg.id());

   dnsResponse.addRecord(DnsSection.QUESTION, question);

   for (int i = 0, count = msg.count(DnsSection.ANSWER); i count; i++) {

   DnsRecord record = msg.recordAt(DnsSection.ANSWER, i);

   if (record.type() == DnsRecordType.A) {

   // just print the IP after query

   DnsRawRecord raw = (DnsRawRecord) record;

   DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord(

   question.name(),

   DnsRecordType.A, 600, Unpooled.wrappedBuffer(ByteBufUtil.getBytes(raw.content())));

   dnsResponse.addRecord(DnsSection.ANSWER, queryAnswer);

   localChannel.writeAndFlush(dnsResponse);

   @Override

   public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) {

   log.error(e.getMessage(), e);

   proxyChannel = b.bind(0).sync().addListener(future1 - {

   log.info("绑定成功");

   }).channel();

   public void send(String domain, int id, Channel localChannel) {

   this.localChannel = localChannel;

   DnsQuery query = new DatagramDnsQuery(null, new InetSocketAddress("114.114.114.114", 53), id).setRecord(

   DnsSection.QUESTION,

   new DefaultDnsQuestion(domain, DnsRecordType.A));

   this.proxyChannel.writeAndFlush(query);

  

 

  三、本地测试

  修改本机DNS设置(win11),修改首选、备选DNS地址为127.0.0.1
 

  打开命令行工具,执行DNS缓存清除命令 ipconfig/flushdns
 

  自此就可以打开浏览器访问常用网站,看是否能正常访问,来验证自建的DNS服务器效果了

  用 Node.js 手写一个 DNS 服务器

  DNS中有哪些值得学习的优秀设计

  netty dns example

  以上就是Java Netty框架自建DNS代理服务器教程(java的netty框架)的详细内容,想要了解更多 Java Netty框架自建DNS代理服务器教程的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: