Java使用Netty框架自建DNS代理服务器教程
前言
DNS协议作为着互联网客户端服务器通信模式得第一关,在当下每天都有成千上亿上网记录产生得当今社会,其重要性自然不可言喻。在国内比较有名得DNS服务器有电信得114。114。114。114、阿里云得223。5。5。5,DNSPod得119。29。29。29,配置一个好的DNS服务器可以缩短请求响应时间、降低DNS劫持概率,提升上网体验。
上面这些都是互联网公用DNS服务器,本文博主教大家使用JavaNetty自建DNS代理服务器,目前网上对于使用Netty自建DNS服务器得教程良莠不齐,大多没有代理步骤,达不到博主想要得代理效果,因而创建此文。觉得本文有帮助得可以关注博主githubhttps:github。comwayn111一、自建DNS代理服务器有哪些优势1。域名控制:对于特定域名可以自由控制访问权限(屏蔽对特定网站访问)2。域名记录:记录局域网内各个主机得域名访问(记录员工上网记录)3。配置内网域名:通过自建DNS服务器可以配置内网域名,节约成本4。DNS负载均衡:通过自建DNS服务器可以轻松实现对于访问域名得负载均衡配置5。。。。二、自建DNS代理服务器代码
1。添加域名黑名单文件,resources文件夹下添加blacklist。txt文件google。com。facebook。com。
初始化BLACKLISTDOMAINprivatestaticfinalListStringBLACKLISTDOMAINnewArrayList();static{Strings;try(InputStreamisDnsServer。class。getClassLoader()。getResourceAsStream(blacklist。txt);BufferedReaderbrnewBufferedReader(newInputStreamReader(is))){while(StrUtil。isNotBlank(sbr。readLine())){BLACKLISTDOMAIN。add(s);}}catch(Exceptione){log。error(e。getMessage(),e);}}
2。使用UDP协议绑定本机53端口,并初始化ProxyUdpDNS请求代理对象Slf4jpublicfinalclassDnsServer{privatestaticfinalListStringBLACKLISTDOMAINnewArrayList();static{。。。}publicstaticvoidmain(String〔〕args)throwsException{ProxyUdpproxyUdpnewProxyUdp();proxyUdp。init();finalint〔〕num{0};finalNioEventLoopGroupgroupnewNioEventLoopGroup();BootstrapbootstrapnewBootstrap();bootstrap。group(group)。channel(NioDatagramChannel。class)。handler(newChannelInitializerNioDatagramChannel(){OverrideprotectedvoidinitChannel(NioDatagramChannelnioDatagramChannel){nioDatagramChannel。pipeline()。addLast(。。。);}})。option(ChannelOption。SOBROADCAST,true);intport53;ChannelFuturefuturebootstrap。bind(port)。addListener(future1{log。info(serverlisteningport:{},port);});future。channel()。closeFuture()。addListener(future1{if(future。isSuccess()){log。info(future。channel()。toString());}});}}
3。给nioDatagramChannel。pipeline()添加ChannelHandlernioDatagramChannel。pipeline()。addLast(newDatagramDnsQueryDecoder());nioDatagramChannel。pipeline()。addLast(newSimpleChannelInboundHandlerDatagramDnsQuery(){OverrideprotectedvoidchannelRead0(ChannelHandlerContextctx,DatagramDnsQuerymsg){try{DefaultDnsQuestiondnsQuestionmsg。recordAt(DnsSection。QUESTION);StringnamednsQuestion。name();log。info(namenum〔0〕);Channelchannelctx。channel();intidmsg。id();channel。attr(AttributeKey。DatagramDnsQueryvalueOf(String。valueOf(id)))。set(msg);if(BLACKLISTDOMAIN。contains(name)){DnsQuestionquestionmsg。recordAt(DnsSection。QUESTION);DatagramDnsResponsednsResponsegetDatagramDnsResponse(msg,id,question);channel。writeAndFlush(dnsResponse);return;}proxyUdp。send(name,msg。id(),channel);}catch(Exceptione){log。error(e。getMessage(),e);}}privateDatagramDnsResponsegetDatagramDnsResponse(DatagramDnsQuerymsg,intid,DnsQuestionquestion){DatagramDnsResponsednsResponsenewDatagramDnsResponse(msg。recipient(),msg。sender(),id);dnsResponse。addRecord(DnsSection。QUESTION,question);DefaultDnsRawRecordqueryAnswernewDefaultDnsRawRecord(question。name(),DnsRecordType。A,600,Unpooled。wrappedBuffer(newbyte〔〕{(byte)192,(byte)168,1,1}));dnsResponse。addRecord(DnsSection。ANSWER,queryAnswer);returndnsResponse;}OverridepublicvoidexceptionCaught(ChannelHandlerContextctx,Throwablee){log。error(e。getMessage(),e);}});nioDatagramChannel。pipeline()。addLast(newDatagramDnsResponseEncoder());
在newSimpleChannelInboundHandler()中解析客户端DNS查询报文,获取访问域名信息,如果访问域名在黑名单中,则通过getDatagramDnsResponse()直接返回192。168。1。1的DNS响应报文,反之则通过proxyUdp对象转发DNS查询。
4。ProxyUdp作为DNS查询代理类会通过send(Stringdomain,intid,ChannelserverChannel)方法传入DnsServer类收到的访问域名、DNS事务ID、serverChannel。随后包装访问域名请求DNS服务器114。114。114。114,最后通过newSimpleChannelInboundHandler()将收到的DNS响应报文通过上一步传入得serverChannel输出到客户端。Slf4jclassProxyUdp{privateChannelserverChannel;privateChannelproxyChannel;publicvoidinit()throwsInterruptedException{EventLoopGroupproxyGroupnewNioEventLoopGroup();BootstrapbnewBootstrap();b。group(proxyGroup)。channel(NioDatagramChannel。class)。handler(newChannelInitializerDatagramChannel(){OverrideprotectedvoidinitChannel(DatagramChannelch){ChannelPipelinepch。pipeline();p。addLast(newDatagramDnsQueryEncoder())。addLast(newDatagramDnsResponseDecoder())。addLast(newSimpleChannelInboundHandlerDatagramDnsResponse(){OverridepublicvoidchannelActive(ChannelHandlerContextctx){log。info(ctx。channel()。toString());}OverrideprotectedvoidchannelRead0(ChannelHandlerContextctx,DatagramDnsResponsemsg){DatagramDnsQuerydnsQuerylocalChannel。attr(AttributeKey。DatagramDnsQueryvalueOf(String。valueOf(msg。id())))。get();DnsQuestionquestionmsg。recordAt(DnsSection。QUESTION);DatagramDnsResponsednsResponsenewDatagramDnsResponse(dnsQuery。recipient(),dnsQuery。sender(),msg。id());dnsResponse。addRecord(DnsSection。QUESTION,question);for(inti0,countmsg。count(DnsSection。ANSWER);icount;i){DnsRecordrecordmsg。recordAt(DnsSection。ANSWER,i);if(record。type()DnsRecordType。A){justprinttheIPafterqueryDnsRawRecordraw(DnsRawRecord)record;DefaultDnsRawRecordqueryAnswernewDefaultDnsRawRecord(question。name(),DnsRecordType。A,600,Unpooled。wrappedBuffer(ByteBufUtil。getBytes(raw。content())));dnsResponse。addRecord(DnsSection。ANSWER,queryAnswer);}}serverChannel。writeAndFlush(dnsResponse);}OverridepublicvoidexceptionCaught(ChannelHandlerContextctx,Throwablee){log。error(e。getMessage(),e);}});}});proxyChannelb。bind(0)。sync()。addListener(future1{log。info(绑定成功);})。channel();}publicvoidsend(Stringdomain,intid,ChannelserverChannel){this。serverChannelserverChannel;DnsQueryquerynewDatagramDnsQuery(null,newInetSocketAddress(114。114。114。114,53),id)。setRecord(DnsSection。QUESTION,newDefaultDnsQuestion(domain,DnsRecordType。A));this。proxyChannel。writeAndFlush(query);}}
5。自建DNS服务器全部代码Slf4jpublicfinalclassDnsServer{privatestaticfinalListStringBLACKLISTDOMAINnewArrayList();static{Strings;try(InputStreamisDnsServer。class。getClassLoader()。getResourceAsStream(blacklist。txt);BufferedReaderbrnewBufferedReader(newInputStreamReader(is))){while(StrUtil。isNotBlank(sbr。readLine())){BLACKLISTDOMAIN。add(s);}}catch(Exceptione){log。error(e。getMessage(),e);}}publicstaticvoidmain(String〔〕args)throwsException{ProxyUdpproxyUdpnewProxyUdp();proxyUdp。init();finalint〔〕num{0};finalNioEventLoopGroupgroupnewNioEventLoopGroup();BootstrapbootstrapnewBootstrap();bootstrap。group(group)。channel(NioDatagramChannel。class)。handler(newChannelInitializerNioDatagramChannel(){OverrideprotectedvoidinitChannel(NioDatagramChannelnioDatagramChannel){nioDatagramChannel。pipeline()。addLast(newDatagramDnsQueryDecoder());nioDatagramChannel。pipeline()。addLast(newSimpleChannelInboundHandlerDatagramDnsQuery(){OverrideprotectedvoidchannelRead0(ChannelHandlerContextctx,DatagramDnsQuerymsg){try{DefaultDnsQuestiondnsQuestionmsg。recordAt(DnsSection。QUESTION);StringnamednsQuestion。name();log。info(namenum〔0〕);Channelchannelctx。channel();intidmsg。id();channel。attr(AttributeKey。DatagramDnsQueryvalueOf(String。valueOf(id)))。set(msg);if(BLACKLISTDOMAIN。contains(name)){DnsQuestionquestionmsg。recordAt(DnsSection。QUESTION);DatagramDnsResponsednsResponsegetDatagramDnsResponse(msg,id,question);channel。writeAndFlush(dnsResponse);return;}proxyUdp。send(name,msg。id(),channel);}catch(Exceptione){log。error(e。getMessage(),e);}}privateDatagramDnsResponsegetDatagramDnsResponse(DatagramDnsQuerymsg,intid,DnsQuestionquestion){DatagramDnsResponsednsResponsenewDatagramDnsResponse(msg。recipient(),msg。sender(),id);dnsResponse。addRecord(DnsSection。QUESTION,question);justprinttheIPafterqueryDefaultDnsRawRecordqueryAnswernewDefaultDnsRawRecord(question。name(),DnsRecordType。A,600,Unpooled。wrappedBuffer(newbyte〔〕{(byte)192,(byte)168,1,1}));dnsResponse。addRecord(DnsSection。ANSWER,queryAnswer);returndnsResponse;}OverridepublicvoidexceptionCaught(ChannelHandlerContextctx,Throwablee){log。error(e。getMessage(),e);}});nioDatagramChannel。pipeline()。addLast(newDatagramDnsResponseEncoder());}})。option(ChannelOption。SOBROADCAST,true);intport553;ChannelFuturefuturebootstrap。bind(port)。addListener(future1{log。info(serverlisteningport:{},port);});future。channel()。closeFuture()。addListener(future1{if(future。isSuccess()){log。info(future。channel()。toString());}});}}Slf4jclassProxyUdp{privateChannellocalChannel;privateChannelproxyChannel;publicvoidinit()throwsInterruptedException{EventLoopGroupproxyGroupnewNioEventLoopGroup();BootstrapbnewBootstrap();b。group(proxyGroup)。channel(NioDatagramChannel。class)。handler(newChannelInitializerDatagramChannel(){OverrideprotectedvoidinitChannel(DatagramChannelch){ChannelPipelinepch。pipeline();p。addLast(newDatagramDnsQueryEncoder())。addLast(newDatagramDnsResponseDecoder())。addLast(newSimpleChannelInboundHandlerDatagramDnsResponse(){OverridepublicvoidchannelActive(ChannelHandlerContextctx){log。info(ctx。channel()。toString());}OverrideprotectedvoidchannelRead0(ChannelHandlerContextctx,DatagramDnsResponsemsg){DatagramDnsQuerydnsQuerylocalChannel。attr(AttributeKey。DatagramDnsQueryvalueOf(String。valueOf(msg。id())))。get();DnsQuestionquestionmsg。recordAt(DnsSection。QUESTION);DatagramDnsResponsednsResponsenewDatagramDnsResponse(dnsQuery。recipient(),dnsQuery。sender(),msg。id());dnsResponse。addRecord(DnsSection。QUESTION,question);for(inti0,countmsg。count(DnsSection。ANSWER);icount;i){DnsRecordrecordmsg。recordAt(DnsSection。ANSWER,i);if(record。type()DnsRecordType。A){justprinttheIPafterqueryDnsRawRecordraw(DnsRawRecord)record;DefaultDnsRawRecordqueryAnswernewDefaultDnsRawRecord(question。name(),DnsRecordType。A,600,Unpooled。wrappedBuffer(ByteBufUtil。getBytes(raw。content())));dnsResponse。addRecord(DnsSection。ANSWER,queryAnswer);}}localChannel。writeAndFlush(dnsResponse);}OverridepublicvoidexceptionCaught(ChannelHandlerContextctx,Throwablee){log。error(e。getMessage(),e);}});}});proxyChannelb。bind(0)。sync()。addListener(future1{log。info(绑定成功);})。channel();}publicvoidsend(Stringdomain,intid,ChannellocalChannel){this。localChannellocalChannel;DnsQueryquerynewDatagramDnsQuery(null,newInetSocketAddress(114。114。114。114,53),id)。setRecord(DnsSection。QUESTION,newDefaultDnsQuestion(domain,DnsRecordType。A));this。proxyChannel。writeAndFlush(query);}}三、本地测试
1。修改本机DNS设置(win11),修改首选、备选DNS地址为127。0。0。1image。png
2。打开命令行工具,执行DNS缓存清除命令ipconfigflushdnsimage。png
自此就可以打开浏览器访问常用网站,看是否能正常访问,来验证自建的DNS服务器效果了
美到极致的二十二个句子1我忧郁地望了望天,悲伤落下了一片一片。2。醉过才知酒浓,爱过才知情重。你不能做我的诗,正如我不能做你的梦。3如果我的结局不是你,夕阳余晖里,连背影都是对不起。4明明是我的风筝,却
寂寞宁古塔已经多少年没有打开过QQ空间了,今天心血来潮翻出了我21岁生日那天写下的这篇文章。只记得那段时间我在看余秋雨的山居笔记对其中的被流放者的土地印象深刻,很长一段时间沉浸在文章中并因此
心心念念的最好生活方式存钱,运动,读书,早起如果你感受到过度的焦虑与彷徨,可能是你看到他人完成了你期许的逆转。他人或是存钱的坚持和金额数字让你艳羡,或是他人运动带给了他人身体上外形的改变,或是他人一如既往地选择坚持阅读,或是
人有三不说,说多损阴德说话谁都会,但要说得好就难了。有时候话说不好,反而会损阴德,带来极大的恶报,有些话我们说时一定要注意。恶语如刀不能说说话是一门艺术,有时候我们在不经意间,就会说出一些伤害别人的话,
颜值控的女人为爱疯狂命归西头条创作挑战赛我要为我的朋友大哭一场,我心疼她,更思念九泉之下的她,她离开我离开这个世界已经快7年了。我想告诉颜值控她,你白死了,你辛辛苦苦买的房有人替你住了,你得了大病都舍不得花
什么是自我内耗?如何改变自我内耗?接纳不完美的自己为什么总有人更快乐更积极?成长性思维和固定性思维的区别是什么?什么是自我内耗?如何改变自我内耗?如何获得高质量的快乐?什么是思维反刍?反省和思维反刍有什么区别?追求完美有错吗?比完
坚持下去,全力以赴自律生活头条创作挑战赛我们这一代人什么事情都想要快从来没有把一件事坚持很久但成功需要时间我希望从今天开始,把跳绳这件事做下去。想要减脂,平常也没什么时间锻炼,跳绳对我来说算便捷的运动方式了
为推动建设开放型世界经济贡献中国力量为推动建设开放型世界经济贡献中国力量国际社会期待习近平主席出席G20领导人第十七次峰会APEC第二十九次领导人非正式会议并访问泰国应印度尼西亚共和国总统佐科邀请,国家主席习近平将于
南航物流双11期间承运国内外货物超28000吨中证网讯(记者王可)11月12日,记者从南方航空物流有限公司(简称南航物流)了解到,双11期间(11月1日11日),南航物流共计承运国内外货物超28000吨其中,国际货物来自天猫国
吉林省的区划变动,9个地级市之一,四平市为何有5个区县?在之前的文章中,已经给大家介绍了很多东北城市的区划变迁调整,东北地区的历史悠久,每个城市的区划调整都非常有意思,今天给大家说一下吉林省四平市的区划变迁调整,看看四平市如何一步步形成
顶级领导力的秘诀就在于两个字赋能优秀的员工难得,优秀的领导者更难得。我们在职场打拼的过程中,也常常关心自己有没有领导力,有没有可能晋升成为一个领导者。很显然,领导力的上限,决定了你在职场上的晋升天花板。然而,尽管