DNS 代理?Pipy:這我也可以

Pipy 是個可編程代理,曾經我們做過?TCP/HTTP 代理、MQTT 代理、Dubbo 代理、Redis 代理、Thrift 代理。前幾天有人問?DNS[1]?的代理能不能做?當然可以,而且 DNS 代理已經應用在?跨集群流量調度?中,文末經對此進行簡單地介紹。

閱讀本文將了解到:

  • ??DNS 的基本介紹以及 DNS 的處理流程

  • ??使用編碼實現一個 DNS 代理

  • ??在代理中增加智能線路解析功能

DNS 介紹

DNS(Domain Name System,域名系統)是互聯網的一項服務。它將域名和 IP 地址相互映射為一個分布式數據庫,能夠使人更方便地訪問互聯網。DNS 使用 TCP 和 UDP 端口 53。

-- 摘自維基百科

024619bc6bbb13fe70935448ba24c9ff.png
dns procedure

簡化版的 DNS 處理流程:

  1. 1.?DNS 客戶端(如瀏覽器、應用程序或者設備)發送域名?example.com?的查詢請求。

  2. 2. DNS 解析器收到請求,查詢本地緩存,如果本地有記錄且未過期會返回本地的記錄。

  3. 3.?如果本地緩存未命中,DNS 解析器將從 DNS 根服務器開始向下查詢,首先是頂級域名(Top Level Domain, TLD) DNS 服務器(這里是?.com),一直向下直到可以解析?example.com?的服務器。

  4. 4.?能夠解析?example.com?的服務器成為權威 DNS 名稱服務器(Authoritative DNS name server),解析器訪問該服務器并收到 IP 地址等相關信息,然后返回給給客戶端。解析完成。

相信在工作的時候會遇到需要改 DNS 記錄來更新域名的真實指向,比如切換運行環境、流量攔截,DNS 也經常作為服務發現的手段之一。通常 DNS 服務器要么是服務提供商業維護,要么就是企業內部的網絡團隊,導致修改 DNS 的解析記錄不夠便利。而且由于 DNS 的緩存設計,每條記錄都有個 TTL 的設置,在緩存失效前都不會再去更新記錄。TTL 過長過短,都不合適。

引入 DNS 代理,可以在解決這個問題的同時,實現更多的功能。

接下來通過案例來演示如何使用 Pipy 實現 DNS 的代理(準確來講,應該是代理和服務器的合體),這個代理會從自定義的記錄中返回 DNS 查詢請求。同時我們還會加入特性:根據客戶端 IP 的地址返回不同的 DNS 記錄,來實現智能線路解析。演示中所使用的腳本,都可以從?這里[2]?下載。

方案

8d5a38fb2f7741d8ccc8c02360621be5.png
dns-proxy

如上圖所示,DNS 代理與原來的解析器,提供類似的功能。但是在緩存失效或者未命中時,會查詢自定義的解析記錄。如果有自定義記錄,就返回自定義記錄;如果沒有,按照原來的流程去 DNS 服務器上查詢。

實現

在開始之前,借助 wireshark 的網絡抓包來看下 DNS 消息的格式,DNS 查詢和應答的消息格式是一樣的,都包含一下四個部分:

  • ??頭部:包含了 ID、標記、查詢的條目數、應答的條目數、權威資源條目數以及附加資源條目數。

  • ??標記部分:這部分標識消息類型、名稱服務器是否權威、 查詢是否遞歸、請求是否被截斷,以及狀態。

  • ??請求部分:包含正在/需要解析的域名和記錄類型(A、AAAA、MX、TXT 等)。域名中的每個標簽都以其長度為前綴。

  • ??應答部分:包含查詢域名的資源記錄。

60df5cfd26cd90fd60e524df241623b8.png
dns-message-format

在?Pipy 0.70.0 的更新?中,假如了 DNS 的解碼器。使用 DNS 解碼器,可以對 DNS 消息進行解碼,解碼出上面的四個部分。

PipJS 編碼

實現的腳本邏輯很簡單,為了方便閱讀將其按功能分成了幾個模塊,實現了?AAAAACNAMEMXTXTNS?幾個常見類型的記錄解析。

├──?cache.js?#緩存
├──?main.js?#主入口腳本
├──?records.js?#自定義記錄的邏輯
├──?records.json?#自定義記錄的內容
├──?smart-line.js?#智能線路解析的邏輯
└──?smart-line.json?#智能線路解析的配置

這里列出?main.js[3]?的部分核心代碼,并對代碼進行了注解:

  1. 1.?首先使用?DNS.decode()?對數據流進行解碼

  2. 2.?然后從結果中找到要查詢域名和類型

  3. 3.?查詢緩存

  4. 4. 緩存未命中,查詢自定義的記錄。

  5. 5.?智能線路解析

  6. 6.?返回響應

  7. 7.?如果 3、4 均查詢不到,會請求上游的 DNS 服務器,然后緩存并返回響應

.listen(5300,?{?protocol:?'udp'?})
.replaceMessage(msg?=>?((query,?res,?record)?=>?(query?=?DNS.decode(msg.body),?//1query?.question?.[0]?.name?&&?query?.question?.[0]?.type?&&?(?//2record?=?getDNS(query.question[0].type?+?'#'?+?query.question[0].name)?//3||?local.query(query.question[0].name,?query.question[0].type)?//4),record???(record?=?line.filter(__inbound.remoteAddress,?record),?//5res?=?{},res.qr?=?res.rd?=?res.ra?=?res.aa?=?1,res.id?=?query.id,res.question?=?[{'name':?query.question[0].name,'type':?query.question[0].type}],record.status?===?'deny'???(res.rcode?=?local.code.REFUSED)?:?(res.answer?=?record.rr),new?Message(DNS.encode(res))?//6)?:?(_forward?=?true,msg)))()
)
.branch(()?=>?_forward,?$?=>?$.connect(()?=>?`${config.upstreamDNSServer}:53`,?{?protocol:?'udp'?})?//7.handleMessage(msg?=>?((res?=?DNS.decode(msg.body))?=>?(res?.question?.[0]?.name?&&?res?.question?.[0]?.type?&&!res?.rcode?&&?(setDNS(res.question[0].type?+?'#'?+?res.question[0].name,{rr:?res.answer,status:?res.rcode?==?local.code.REFUSED???'deny'?:?null}))))()),$?=>?$
)

自定義記錄

下面是自定義記錄的內容,與 DNS 應答的格式類似。為了支持智能線路解析,部分記錄增加了標簽信息:"labels": ["line1"]

[{"name":?"example.com","type":?"A","ttl":?60,"rdata":?"192.168.139.10","labels":?["line1"]},{"name":?"example.com","type":?"A","ttl":?60,"rdata":?"192.168.139.11","labels":?["line2"]},...{"name":?"example.com","type":?"MX","ttl":?600,"rdata":?{"preference":?10,"exchange":?"mail2.example.com"}},{"name":?"example.com","type":?"TXT","ttl":?600,"rdata":?"hi.pipy!"},{"name":?"example.com","type":?"NS","ttl":?600,"rdata":?"ns1.example.com"},...
]

智能線路解析

智能線路解析的邏輯比較簡單,為不同的 IP 范圍設置線路標簽,在應答時如果記錄帶有標簽就只返回對應標簽的記錄。

{"line1":?["192.168.1.110/32"],"line2":?["127.0.0.1/32"]
}

測試

啟動代理:

$?pipy?main.js

如上面配置所示,127.0.0.1?是本機回環網卡的地址,192.168.1.110?本機以太網卡的地址,代理監聽在?5300?端口。

首先使用?localhost?訪問代理,這樣代理獲取的客戶端 IP 地址為?127.0.0.1,在查詢?example.com?的記錄時,直返回來地址對應的線路?line2?的記錄?192.168.139.11

$?dig?@localhost?-p?5300?a?example.com;?<<>>?DiG?9.10.6?<<>>?@localhost?-p?5300?a?example.com
;?(2?servers?found)
;;?global?options:?+cmd
;;?Got?answer:
;;?->>HEADER<<-?opcode:?QUERY,?status:?NOERROR,?id:?25868
;;?flags:?qr?aa?rd?ra;?QUERY:?1,?ANSWER:?1,?AUTHORITY:?0,?ADDITIONAL:?0;;?QUESTION?SECTION:
;example.com.???IN?A;;?ANSWER?SECTION:
example.com.??60?IN?A?192.168.139.11;;?Query?time:?0?msec
;;?SERVER:?127.0.0.1#5300(127.0.0.1)
;;?WHEN:?Tue?Dec?13?21:09:38?CST?2022
;;?MSG?SIZE??rcvd:?56

接著使用?192.168.1.110?訪問代理,這次客戶端的地址為?192.168.1.110,返回的是線路?line1?的記錄?192.168.139.10

$?dig?@192.168.1.110?-p?5300?a?example.com;?<<>>?DiG?9.10.6?<<>>?@192.168.1.110?-p?5300?a?example.com
;?(1?server?found)
;;?global?options:?+cmd
;;?Got?answer:
;;?->>HEADER<<-?opcode:?QUERY,?status:?NOERROR,?id:?54165
;;?flags:?qr?aa?rd?ra;?QUERY:?1,?ANSWER:?1,?AUTHORITY:?0,?ADDITIONAL:?0;;?QUESTION?SECTION:
;example.com.???IN?A;;?ANSWER?SECTION:
example.com.??60?IN?A?192.168.139.10;;?Query?time:?0?msec
;;?SERVER:?192.168.1.110#5300(192.168.1.110)
;;?WHEN:?Tue?Dec?13?21:12:37?CST?2022
;;?MSG?SIZE??rcvd:?56

假如我從另外一臺機器上訪問,因為沒有設置線路,會返回兩條記錄。

$?dig?@192.168.1.110?-p?5300?a?example.com;?<<>>?DiG?9.16.1-Ubuntu?<<>>?@192.168.1.110?-p?5300?a?example.com
;?(1?server?found)
;;?global?options:?+cmd
;;?Got?answer:
;;?->>HEADER<<-?opcode:?QUERY,?status:?NOERROR,?id:?64873
;;?flags:?qr?aa?rd?ra;?QUERY:?1,?ANSWER:?2,?AUTHORITY:?0,?ADDITIONAL:?0;;?QUESTION?SECTION:
;example.com.???IN?A;;?ANSWER?SECTION:
example.com.??60?IN?A?192.168.139.10
example.com.??60?IN?A?192.168.139.11;;?Query?time:?0?msec
;;?SERVER:?192.168.1.110#5300(192.168.1.110)
;;?WHEN:?Tue?Dec?13?13:15:24?UTC?2022
;;?MSG?SIZE??rcvd:?83

因為只設置了 A 記錄的線路,其他類型的記錄不受影響。

$?$dig?@localhost?-p?5300?mx?example.com;?<<>>?DiG?9.10.6?<<>>?@localhost?-p?5300?mx?example.com
;?(2?servers?found)
;;?global?options:?+cmd
;;?Got?answer:
;;?->>HEADER<<-?opcode:?QUERY,?status:?NOERROR,?id:?33492
;;?flags:?qr?aa?rd?ra;?QUERY:?1,?ANSWER:?2,?AUTHORITY:?0,?ADDITIONAL:?0;;?QUESTION?SECTION:
;example.com.???IN?MX;;?ANSWER?SECTION:
example.com.??600?IN?MX?10?mail1.example.com.
example.com.??600?IN?MX?10?mail2.example.com.;;?Query?time:?0?msec
;;?SERVER:?127.0.0.1#5300(127.0.0.1)
;;?WHEN:?Tue?Dec?13?21:18:27?CST?2022
;;?MSG?SIZE??rcvd:?117

進階

對 Pipy 有一定了解的小伙伴可能知道?Repo 模式[4],有興趣的可以參考這篇文章?快速入門 Pipy Repo(文章一年前發布,界面和 API 接口有更新,但是原理不變)。

使用 Repo 模式,所有主機上的代理(或者稱之為 DNS 服務器)都從 Repo 中實時獲取自定義記錄的更新,并刷新緩存。

礙于篇幅,這里就不深入。有興趣的小伙伴可以嘗試自己實現。

5a6b8d5b916b13d43b63bf7f2e85515e.png
dynamic-dns-resolve

總結

至此 Pipy 可以實現的代理又增加了一種。DNS 的應用無處不在,也正因如此從 DNS 層面可以解決問題。

讓我們再回到開頭提到的問題,在?跨集群流量調度實戰?的 demo 中,我們將輕松將請求流量調度到了其他集群進行處理。請求的地址是?http://httpbin.httpbin:8080/,這里的?httpbin.httbin?是命名空間?httpbin?下 K8s Service?httpbin?的域名。但是在集群?cluster-2?中并沒有這個 Service,僅在集群?cluster-1?和?cluster-3?中部署,這個地址在集群?cluster-2?中無法解析。

這里使用了個小手段,在網格的初始化容器設置 iptables 規則攔截流量時,也 DNS 的流量也攔截到 sidecar 實現的 DNS 代理(監聽在?127.0.0.153:5300),通過自定義 DNS 記錄實現業務流量的攔截。

ff11eb3d7159c89d386a9f1f8f98d660.png
fsm-multi-cluster

引用鏈接

[1]?DNS:?https://en.wikipedia.org/wiki/Domain_Name_System
[2]?這里:?https://github.com/flomesh-io/pipy-demos/tree/main/pipy-dns-demo
[3]?main.js:?https://github.com/flomesh-io/pipy-demos/blob/main/pipy-dns-demo/main.js
[4]?Repo 模式:?https://flomesh.io/pipy/docs/en/operating/repo/0-intro

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/280292.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/280292.shtml
英文地址,請注明出處:http://en.pswp.cn/news/280292.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何在Windows中快速輕松地將文件發送到SkyDrive

We have already shown you how you can share external folders with your SkyDrive, but what if you actually want to copy a file or folder into your SkyDrive folder? Of course copying and pasting is nowhere near geeky enough, so here’s how to add a SkyDrive…

性能測試一些相關的概念

1.壓測任務需求的確認 確定好工作范圍&#xff1a; 首先分析壓測最容易出現瓶頸的地方&#xff0c;有目的的進行測試。 用戶更關心整個系統中哪個環節的性能情況也會影響工作范圍。2. 壓力測試 通過不斷加壓被測系統&#xff0c;直到性能指標達到飽和&#xff0c;這種測試能夠找…

阿里云雙11全球狂歡節 計算資源買買買

本文講的是阿里云雙11全球狂歡節 計算資源買買買【IT168資訊】除了喜歡屯奶粉和運動裝備的消費者外&#xff0c;創業者也能加入雙11“買買買”狂歡。11月2日&#xff0c;阿里云宣布加入天貓雙11全球狂歡節&#xff0c;全線計算資源產品在官網狂歡售賣&#xff0c;與創業者共同打…

windows刪除桌面ie_從Windows 8“開始”屏幕啟動IE的桌面版本

windows刪除桌面ieThere are two versions of Internet Explorer in Windows 8, one you can only launch from the Start Screen and the Desktop version which you can only launch from the Desktop. Lets look at how we can launch the Desktop version from the Start S…

如何讓程序跑起來――第三章

下面是我看完第三章之后總結出來的知識點&#xff1a;整數和小數沒有太大的差別&#xff0c;是因為計算機內部所有信息都是以二進制數的形式來處理的&#xff0c;但使用二進制表示整數和小數的方法基本相同&#xff0c;比如小數點前和小數點后將個數位的數值和位全相乘的結果相…

.NET Conf China 2022 圓滿落幕,明年再見!

時光飛快&#xff0c;還記得本月的第一個周末嗎&#xff1f;12月3日-12月4日&#xff0c;相信對于 .NET 開發者來說一定記憶猶新&#xff01;.NET Conf China 2022 于12月4日圓滿落幕。八方助力共譜大會盛宴.NET Conf China 2022 是一個社區性質的技術峰會&#xff0c;本次大會…

移動端手指操控左右滑動的菜單

<!DOCTYPE html> <html lang"en"> <head> <meta name"viewport" content"widthdevice-width, initial-scale1.0, maximum-scale1.0, user-scalable0"> <meta charset"UTF-8"> <title>移動端…

馬哥linux高薪中級-DNS

第一章 簡介一、DNSdomain name server&#xff0c;用來將計算機名稱或者域名解析成ip地址的服務協議。用戶在使用域名訪問時會先通過DNS服務請求域名對應的ip地址&#xff0c;然后緩存下來&#xff0c;然后才通過ip地址進行通信。最初域名解析是通過HOSTS文件來靜態綁定的。DN…

愚蠢的怪胎技巧:通過命令行管理SkyDrive

Originally launched as an April Fools prank by the Microsoft SkyDrive team, SkyCMD turned out to be a really geeky way to manage files and folders on your SkyDrive from the command line. Lets take a quick look. SkyCMD最初是由Microsoft SkyDrive團隊以愚人節惡…

關于vue父子組件之間事件觸發及數據傳遞問題

父組件&#xff1a;1&#xff0c;引入子組件2&#xff0c;ref 3&#xff0c;需要更新數據操作的地方 子組件&#xff1a;1&#xff0c;定義同名事件&#xff0c;拿到數據執行相關操作

.NET Core如何通過認證機制訪問Kafka?

【.NET Core】| 總結/Edison Zhou大家好&#xff0c;我是Edison。最近有一個ASP.NET Core使用認證機制訪問Kafka的需求&#xff0c;加之我們又使用了CAP這個開源項目使用的Kafka&#xff0c;于是網上尋找了一番發現對應資料太少&#xff0c;于是調查了一番&#xff0c;做了如下…

JQuery框架2.位置屬性|篩選方法|事件

1、位置屬性 jquery的css position獲取匹配元素相對父元素的偏移位置&#xff1b;offset獲取匹配元素在當前視口的相對偏移,返回的對象包含兩個整型屬性&#xff1a;top 和 left $("p").offset() $(div).offset().top $("p").offset().left scrollTop獲取匹…

新手學習Java必需要知道的這些基本概念!

學習好比蓋房子&#xff0c;打地基好很重要&#xff0c;房了能蓋多高關鍵看地基&#xff1b;學習同樣道理&#xff0c;基礎知識是以后學習一切技術的必要條件&#xff0c;我們在準備學習一門開發語言時&#xff0c;首先要學習它的基礎&#xff0c;不僅要會&#xff0c;更要融會…

jenkins沒安裝git報錯

Jenkins新建項目中源碼管理使用Git時遇到如下問題&#xff1a; 在安裝jenkins服務器上查看一下git版本&#xff0c;可能沒有安裝git 也可能是git版本太低 [rootlocalhost nnnnn]# git --version git version 1.8.3.1 yum安裝的版本太低了 打開Jenkins的 主頁面 > 系統管理 …

如何使用 IdGen 生成 UID

在分布式系統中&#xff0c;雪花 ID 是一種常用的唯一 ID 生成算法。它通過結合時間戳、機器碼和自增序列來生成 64 位整數 ID&#xff0c;可以保證 ID 的唯一性和順序性。在.Net 項目中&#xff0c;我們可以使用 IdGen 這個類庫來生成雪花 ID。它是一個開源的類庫&#xff0c;…

mac 不能連接wi-fi_如何在Mac OS X中查看當前的Wi-Fi連接速度

mac 不能連接wi-fiEver since I’ve been using my new MacBook Air, I’ve been befuddled by how to do some of the simplest tasks in Mac OS X that I would normally do from my Windows laptop—like show the connection speed for the current Wi-Fi network. So am I…

User Stories - 最佳實踐 (Best Practices)

在轉向敏捷之后&#xff0c;很多團隊開始使用“用戶故事”一詞。用戶故事是一種簡單而優雅的技術&#xff0c;可以收集客戶需求。然而&#xff0c;它需要一定的理解和實踐才能用User Stories構建出色的軟件。 讓我們仔細看看用戶故事是什么以及如何使用這種技術取得成功。 什么…

聊一聊promise的前世今生

promise的概念已經出現很久了&#xff0c;瀏覽器、nodejs都已經全部實現promise了。現在來聊&#xff0c;是不是有點過時了&#xff1f; 確實&#xff0c;如果不扯淡&#xff0c;這篇隨筆根本不會有太多內容。所以&#xff0c;我就盡可能的&#xff0c;多扯一扯&#xff0c;聊一…

chromebook刷機_如何在Chromebook上切換(或離開)Canary頻道

chromebook刷機Just like Chrome, Google offers multiple channels of the Chrome OS operating system. In addition to the standard Stable, Beta, and Developer channels you can choose from on the About page, there’s a special bleeding-edge Canary channel. The …

C++--day05

目錄: 1. C的提高 1-131P 時間七天 2. C的基礎 132-286P 時間八天 3. C的提高 287-378P 時間五天 4. C/C的數據結構 379-482P 時間五天 5. C/C的設計模式基礎 483-540P 時間三天 視頻資料&#xff1a;https://www.bilibili.com/video/av27904891?fromsearch&seid108915144…