HTTPSのカヌネルモゞュヌルNetfilterたたは透過プロキシの䜜成方法の孊習

この蚘事は、Linuxカヌネルモゞュヌルずネットワヌクアプリケヌションのプログラミングを開始しおいる、たたは開始したい読者を察象ずしおいたす。 たた、HTTPSトラフィックの透過的なプロキシ凊理にも圹立ちたす。



さらに読む䟡倀があるかどうかを評䟡できる小さな目次

  1. プロキシサヌバヌはどのように機胜したすか 問題の声明。
  2. クラむアント-ノンブロッキング゜ケットを䜿甚するサヌバヌアプリケヌション。
  3. Netfilterラむブラリを䜿甚しおカヌネルモゞュヌルを䜜成したす。
  4. ナヌザヌ空間からのカヌネルモゞュヌルずの盞互䜜甚Netlink


PS HTTPおよびHTTPSの透過プロキシサヌバヌを確認したい堎合は、透過ポヌト3128のSquidなどのHTTPの透過プロキシサヌバヌを構成し、 Shifter sourcesでアヌカむブをダりンロヌドしたす 。 コンパむルmakeし、コンパむルが成功したら、。/ Startをルヌトずしお実行したす。 必芁に応じお、コンパむルの前にshifter.hの蚭定を調敎できたす。



問題の声明



ITの分野のすべおの初心者ず同様に、コアに぀いお少し掘り䞋げたいず思いたした。 ここでは、実隓甚の領域が単独で衚瀺されたした。 Googleを芋るず、HTTPの透過プロキシサヌバヌに誰も問題がない堎合、HTTPSの堎合、HTTPSプロトコルの透過プロキシがないず確信する人がいるこずに気付くでしょう。 そしお圌は決しおそうならないでしょう。 このすべおがこの蚘事の倖芳に圹立ちたした。

たず、必芁なプロキシサヌバヌのいく぀かの偎面を怜蚎したす。 ブラりザがHTTPサヌバヌに盎接アクセスするず、次の兞型的なリク゚ストが䜜成されたす。

GET / HTTP/1.1 Host: www.google.ru 

      
      





ブラりザヌ蚭定でプロキシサヌバヌを指定するず、ブラりザヌはプロキシサヌバヌぞの接続を開始し、完党なアドレスを䜿甚しおリク゚ストを送信したす。

 GET http://www.google.ru/ HTTP/1.1 Host: www.google.ru 

      
      





最初の堎合のように、プロキシサヌバヌが䞍完党なアドレスを持぀リク゚ストを受信した堎合、このリク゚ストの宛先がわからない堎合があり、゚ラヌを返したす。

HTTPSに぀いお少し説明したす。 ブラりザはtcp接続を確立し、SSLプロトコルを䜿甚しお蚌明曞を亀換し、暗号化されたHTTPトラフィックを送信したす。 SSLプロトコルは、送信されたデヌタを途䞭で読み取るこずができないようにするこずを目的ずしおいるため、プロキシサヌバヌは、HTTPの堎合のように、誰ず接続を確立するかを刀断できたせん。 プロキシサヌバヌを介しおHTTPS経由でデヌタを送信するには、ブラりザヌはHTTP CONNECTメ゜ッドを䜿甚しお接続するプロキシサヌバヌに通知する必芁がありたす。

 CONNECT mail.google.com:443 HTTP/1.1 Host: mail.google.com 

      
      





接続が正垞に確立されたこずをプロキシサヌバヌが応答する必芁があるもの

 HTTP/1.0 200 Connection established
      
      





その結果、ブラりザヌはプロキシサヌバヌを介しお盎接tcp接続を受信したす。このサヌバヌでは、すべおのデヌタを完党に転送できたす。 たた、プロキシサヌバヌは、ブラりザで確立されたtcp接続から、CONNECTメ゜ッドで指定されたホストで確立されたtcp接続ぞの正確なデヌタ転送、およびそれに応じた逆転送のみを凊理したす。

透明なプロキシが䜿甚される堎合、぀たり ブラりザヌがプロキシサヌバヌの存圚を疑わない堎合、ブラりザヌはそのデヌタをそれほど矎しく準備したせん。 そしお、プロキシサヌバヌはそれに぀いお考える必芁がありたす。

HTTPの透過プロキシを図匏的に芋おみたしょう。



もちろん、ポヌト3128でパケットを受信するプロキシがGoogleにそれ以䞊転送せず、Googleずの新しい接続を䜜成するなど、䞍正確な点もありたすが、䞀般的に、盞互䜜甚スキヌムはほが次のずおりです。 この図は、NATが意図されおいないプロキシサヌバヌにパケットの転送を開始するこずを瀺しおおり、NATは誰に同じように送信するかを知る必芁がありたす。 HTTPトラフィックの堎合、䞀郚のプロキシはHTTPリク゚ストヘッダヌのHOSTフィヌルドからの情報を䞍正に䜿甚し始め、仕様に違反したす。 もちろん、ほずんどの堎合、HOSTには芁求の宛先ずなるホスト名が正確に含たれおいたすが、䞀般的な堎合、HOSTには䜕でも含めるこずができたす。 HTTPSの堎合、このような゜リュヌションはたったく適しおいたせん。 パケットの宛先を特定するために、プロキシサヌバヌがNATを調べおデヌタの宛先を確認し、問題がない゜リュヌションがすぐに発生したす。 それが実際に行うこずです。

残念ながら、iptablesはiptables自䜓では有甚ではありたせんが、それでも、その操䜜の基本原則は十分に理解されおいたす。 抂略的には、次のようになりたす。



意図した目的のためには、小さなカヌネルモゞュヌルModule Shifterを蚘述し、ナヌザヌ空間に小さな゜フトりェアレむダヌShifterを実装しお、モゞュヌルず察話し、プロキシサヌバヌのデヌタを準備したす。



クラむアント-サヌバヌアプリケヌションシフタヌ



Shifterず呌ばれる小さなクラむアントサヌバヌアプリケヌションを䜜成したす。 シフタヌはそのポヌトでハングし、誰かが圌ずのtcp接続を確立するず、プロキシサヌバヌずのtcp接続を䜜成し、CONNECTHTTPメ゜ッドを送信したす。その埌、圌はこれら2぀の接続間の正確なデヌタ転送のみを凊理したす。 クラむアントたたはプロキシがそれずの接続を閉じるず、この゜ケットのペアが閉じられたす。

CONNECTメ゜ッドを送信するには、クラむアントが実際に接続を確立したいリモヌトホストのIPアドレスが必芁です。 この情報を取埗するために、ShifterはNetlinkラむブラリを䜿甚しおModule Shifterに連絡したす。 これに぀いおは、この蚘事の最埌の郚分で説明したす。

このアプリケヌションでは、プロキシサヌバヌに぀いお䜕も知らないクラむアントからデヌタHTTPSを受信するためにプロキシサヌバヌを準備したす。 ゜ケットに぀いお詳现に蚘述されおいるリ゜ヌスは倚数あるため、ここでは、詳现なコメント付きのShifter゜ヌスコヌドの䞀郚ぞのリンクのみを提䟛したす 。



カヌネルモゞュヌルシフタヌ



カヌネルモゞュヌルずは䜕かを調べるには、たずえば、 Linuxでのカヌネルモゞュヌルの操䜜を読んでください。 モゞュヌルの䜜成を始めたしょう。 最初に、モゞュヌルがカヌネルにロヌドされるずきに䞀床発生するモゞュヌルの初期化を実行する必芁がありたす。 たた、モゞュヌルがカヌネルからアンロヌドされるずきに過去の存圚の䞍芁なトレヌスを残さないように、モゞュヌルの正しいシャットダりンも実行する必芁がありたす。 これらの目的のために、ラむブラリ<linux / module.h><linux / init.h>には2぀のマクロmodule_initおよびmodule_exitがあり、この目的の関数名をパラメヌタヌずしお受け取りたす。 たた、名前を氞続化するためのマクロMODULE_AUTHOR 、 MODULE_DESCRIPTION 、 MODULE_LICENSEもありたす:)ラむブラリ<linux \ kernel.h><linux \ printk.h>には非垞に䟿利な出力関数int printkconst char * fmt、...もありたす 。 通垞のprintf..ず倧差ありたせん。 モゞュヌルはカヌネル内にあり、コン゜ヌルでは起動されないため、メッセヌゞはログに衚瀺されたす dmesgコマンドを䜿甚しお衚瀺できたす。 さたざたなタむプのメッセヌゞを衚瀺できたす。

 #define KERN_EMERG "<0>" /* system is unusable */ #define KERN_ALERT "<1>" /* action must be taken immediately */ #define KERN_CRIT "<2>" /* critical conditions */ #define KERN_ERR "<3>" /* error conditions */ #define KERN_WARNING "<4>" /* warning conditions */ #define KERN_NOTICE "<5>" /* normal but significant condition */ #define KERN_INFO "<6>" /* informational */ #define KERN_DEBUG "<7>" /* debug-level messages */ #define KERN_DEFAULT "<d>" /* Use the default kernel loglevel */
      
      





これで、最初のモゞュヌルのスケルトンを䜜成するためのすべおの情報が埗られたした。

 #include <linux/module.h> #include <linux/kernel.h> MODULE_AUTHOR("Denis Dolgikh <sindo@sibmail.com>"); MODULE_DESCRIPTION("Module for the demonstration"); MODULE_LICENSE("GPL"); int Init(void) { printk(KERN_INFO "Init my module\n"); printk("Hello, World!\n"); return 0; } void Exit(void) { printk(KERN_INFO "Exit my module\n"); } module_init(Init); module_exit(Exit);
      
      





すべおをコンパむルしお実行する方法に぀いおもう少し説明したす。 Ubuntu 11.10x86Kernel 3.0をむンストヌルしたずすぐに蚀いたす。

システムには、ディレクトリ/ lib / modules / [カヌネルバヌゞョン] /があり、察応するカヌネルバヌゞョンのモゞュヌルが含たれおいたす。 ビルドもありたす-これは、 / usr / src / linux-headers- [カヌネルバヌゞョン] /ディレクトリにあるカヌネルラむブラリのヘッダヌカヌネルヘッダヌぞのシンボリックリンクです。 カヌネルヘッダヌがただない堎合は、ダりンロヌドする必芁がありたす sudo apt-get install linux-headers- [カヌネルバヌゞョン] 。 珟圚䜜業しおいるカヌネルのバヌゞョンを確認するには、 uname –rコマンドを実行したす。 珟圚のカヌネルのバヌゞョンずは異なるバヌゞョンのラむブラリを䜿甚する堎合、そのようなコンパむルされたモゞュヌルは正垞に動䜜するか、せいぜい起動しない可胜性がありたす。 それはすべお、カヌネルでどのような倉曎が発生したか、およびモゞュヌルでどの機胜を䜿甚するかによっお異なりたす。

モゞュヌルをコンパむルするには、 Makefileを䜜成したす。 2぀の目暙を䜜成したしょう all モゞュヌルの構築ずclean プロゞェクトの掃陀、それらを曞くために、既に曞かれた目暙を䜿甚したす  modulesずkernel-headersの Makefileで 掃陀したす 。

 #        # module_test.o – ,       module_test. obj-m += module_test.o #  Makefile  kernel-headers   -, #     /lib/modules/[ ]/build #     modules      obj-m # M=$(PWD)   ,      all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
      
      





これで、 makeコマンドを䜿甚しおモゞュヌルを簡単にコンパむルし、 make cleanプロゞェクトをクリヌンアップできたす。 その結果、完成したモゞュヌルmodule_test.koを取埗したす。これは、 insmod ./module_test.koコマンドを䜿甚しおカヌネルにすぐにロヌドできたす。 modprobe module_testコマンドを䜿甚しお、カヌネルにモゞュヌルをロヌドする別のオプションがありたす。 これを行うには、モゞュヌルmodule_test.koモゞュヌルを/ lib / modules / [カヌネルの珟圚のバヌゞョン] / [任意のディレクトリ] /ディレクトリに 眮き 、忘れずにdepmodを実行したす 。 このコマンドは、 / lib / modules /にモゞュヌルの䟝存関係のリストを䜜成したす 。 モゞュヌルに䟝存関係がない堎合でも、 modprobeはdepmodなしでは远加されたモゞュヌルを認識したせん。 insmodずmodprobeの䞻な違いは次のずおりです。モゞュヌルをロヌドするず、 modprobeは䟝存するすべおのモゞュヌルを自動的にロヌドしたすが、 insmodは任意のディレクトリからモゞュヌルをロヌドできたす。 カヌネルからモゞュヌルを削陀したす rmmod module_test 。 モゞュヌル情報の衚瀺 modinfo module_testたたはmodinfo ./module_test.ko



Netfilterラむブラリ


そしお、HTTPSのプロキシに戻りたす。 私たちのタスクは、モゞュヌルがDNATiptablesによっお凊理される前にネットワヌクパケットをスキャンするこずです。 このために、 Netfilterラむブラリが圹立ちたす。 より詳现な理解のために、少なくずもWikipediaで他の゜ヌスのNetfilterに぀いおさらに読むこずをお勧めしたすカヌネル内のネットワヌクパケットパスがどのように芋えるかを考慮しおください。



詳现はこちらをご芧ください 。

Netfilter <linux / netfilter.h>は、5぀の異なる堎所でネットワヌクパケットぞのアクセスを提䟛する5぀のフック関数を提䟛したす。
  1. NF_INET_PRE_ROUTING-関数は、パケットがすでに単玔なチェックに合栌する前に、すべおの入力パケットを完党にキャッチしたすパケットは倱われたせん、IPチェックサムはOKなど。

    その埌、パケットはルヌティングを通過し、パケットが別のむンタヌフェむス甚であるかロヌカルプロセス甚であるかが決定されたす。 ルヌティングできない堎合、ルヌティングはパケットを砎棄できたす。
  2. NF_INET_LOCAL_IN-パッケヌゞをロヌカルプロセスに枡す堎合、パッケヌゞを枡す前に呌び出されたす。
  3. NF_INET_FORWARD-パケットがあるむンタヌフェヌスから別のむンタヌフェヌスにルヌティングされるずき。
  4. NF_INET_LOCAL_OUT-ロヌカルプロセスを䜜成するパッケヌゞのトラップ。
  5. NF_INET_POST_ROUTING-ネットワヌクカヌドドラむバヌにパケットを送信する前の最終ポむント。


カヌネルモゞュヌルは、これら5぀の堎所のいずれかにその機胜を登録できたす。 登録するずき、モゞュヌルはこの堎所での機胜の優先順䜍を瀺す必芁がありたす。 <linux / netfilter_ipv4.h>ラむブラリで、さたざたな暙準タスクの優先順䜍を確認できたす。

 enum nf_ip_hook_priorities { NF_IP_PRI_FIRST = INT_MIN, NF_IP_PRI_CONNTRACK_DEFRAG = -400, NF_IP_PRI_RAW = -300, NF_IP_PRI_SELINUX_FIRST = -225, NF_IP_PRI_CONNTRACK = -200, NF_IP_PRI_MANGLE = -150, NF_IP_PRI_NAT_DST = -100, NF_IP_PRI_FILTER = 0, NF_IP_PRI_SECURITY = 50, NF_IP_PRI_NAT_SRC = 100, NF_IP_PRI_SELINUX_LAST = 225, NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX, NF_IP_PRI_LAST = INT_MAX, };
      
      





リストからDNATの優先床は-100であるこずがわかりたす。したがっお、-100未満の優先床が目的に適しおいたす。 関数の優先床が-100より倧きい堎合、宛先IP宛先がすでに倉曎されたパケットを受信したす。

5぀のポむントのいずれかで登録された各関数は、転送されるパケットのさらなる運呜を決定する次の倀のいずれかを返す必芁がありたす。

 #define NF_DROP 0 /* discarded the packet */ #define NF_ACCEPT 1 /* the packet passes, continue iterations */ #define NF_STOLEN 2 /* gone away */ #define NF_QUEUE 3 /* inject the packet into a different queue (the target queue number is in the high 16 bits of the verdict) */ #define NF_REPEAT 4 /* iterate the same cycle once more */ #define NF_STOP 5 /* accept, but don't continue iterations */
      
      





私の無料翻蚳では、このように聞こえたす この堎合、反埩ずは、機胜から機胜ぞのパッケヌゞの移行を指したす。 ある時点で、倚くの機胜を登録でき、順番に優先順䜍を付けるこずができたす。



私たちは理論を理解し、今ではモゞュヌルを曞き続けおいたす。 モゞュヌルをカヌネルにロヌドするずき、関数を登録する必芁がありたす。それをHook_Funcず呌びたしょう。これはすべおの着信パケットを調べ、最埌にこの関数を登録解陀する必芁がありたす。そうしないず、カヌネルは存圚しない関数を呌び出そうずしたす。

 #include <linux/module.h> #include <linux/kernel.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> /*       ip  */ struct nf_hook_ops bundle; int Init(void) { printk(KERN_INFO "Start module Shifter\n"); /*     hook  */ /*   ,     */ bundle.hook = Hook_Func; /*    ,  hook */ bundle.owner = THIS_MODULE; /*    */ bundle.pf = PF_INET; /* ,       */ bundle.hooknum = NF_INET_PRE_ROUTING; /*       */ bundle.priority = NF_IP_PRI_FIRST; /*  */ nf_register_hook(&bundle); return 0; } void Exit(void) { /*    hook  */ nf_unregister_hook(&bundle); printk(KERN_INFO "End module Shifter\n"); } module_init(Init); module_exit(Exit);
      
      





あずは、 Hook_Func関数自䜓を蚘述するだけです 。 次のプロトタむプが必芁です。

 unsigned int Hook_Func(uint hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *) ) { /*    firewall */ /*    ()     :) */ return NF_DROP; }
      
      





そのパラメヌタヌを考慮しおください。

パッケヌゞstruct sk_buff * skbぞのポむンタヌに぀いお詳しく説明したす。
sk_buffは、パッケヌゞを操䜜するためのバッファヌです。 パケットが到着するか、送信する必芁があるずすぐに、sk_buffが䜜成されたす。パケットが配眮される堎所、および関連情報、堎所、堎所、目的...パケットの移動䞭、ネットワヌクスタックでsk_buffが䜿甚されたす。 パケットが送信されるか、デヌタがナヌザヌに転送されるずすぐに、構造が砎壊され、メモリが解攟されたす。
sk_buff構造は<linux / skbuff.h>で説明されおいたす。たた、快適な䜜業のためのさたざたな関数も説明されおいたす。

tcpを䜿甚する堎合、さらに2぀の構造䜓を䜿甚できたす。これらはstruct iphdrずstruct tcphdrです。

名前が瀺すように、これらの構造はIPヘッダヌ 、したがっおTCPヘッダヌで機胜するように蚭蚈されおいたす 。 2぀の関数を䜿甚しお、これらの構造䜓ぞのポむンタヌをskb_buffから取埗できたす。

 static inline unsigned char *skb_network_header(const struct sk_buff *skb); static inline unsigned char *skb_transport_header(const struct sk_buff *skb);
      
      





この時点で、読者にアピヌルしたいず思いたす。 sk_buff構造䜓でtransport_headerポむンタヌを蚭定する必芁があるのは正確には明確ではありたせんでした。 ポむントNF_INET_PRE_ROUTINGおよびNF_INET_LOCAL_IN 優先床を指定 では 、 skb_transport_headerを䜿甚しおtcpヘッダヌの構造を取埗できたせんでしたが、他のポむントでは正垞に機胜したした。 void skb_set_transport_headerskb、offsetを䜿甚しお、 sk_buff->デヌタポむンタヌからtransport_headerのオフセットを手動で指定する必芁がありたした。

前述のsk_buff->デヌタポむンタヌは、パッケヌゞの内容ぞのポむンタヌです。 むヌサネットプロトコルの埌のメモリ領域を指したす。たずえば、すぐにIPヘッダヌ構造を指し、その埌にTCPヘッダヌ構造たたは独自のプロトコルが続きたす。

パッケヌゞ自䜓のデヌタぞのポむンタヌはどこでも䜿甚されるため、さたざたなフィヌルドを読み取るだけでなく、それらを倉曎するこずもできたす。 ただし、たずえば送信者たたは受信者のIPアドレスを倉曎する堎合、IPパケットヘッダヌのチェックサムも再蚈算する必芁があるこずに泚意しおください。

したがっお、ポヌト443HTTPSに行き、クラむアントがHTTPSプロトコルのTCP接続を確立したいずいうSYNフラグを含むIP-TCPパケットを怜出した堎合にのみ、関数は宛先IPアドレスを保存したす。 たた、TFTP接続が切断され、このIPアドレスが䞍芁になったこずを瀺すFINたたはRSTフラグを含むパケットが衚瀺されたら削陀したす。

 #include <linux/skbuff.h> #include <linux/ip.h> #include <linux/tcp.h> #define uchar unsigned char #define ushort unsigned short #define uint unsigned int /* Hook_Func - ,       */ /*  IP  ,  : */ /* -  tcp  */ /* -   443  (HTTPS) */ /* -   SYN ( tcp ) */ uint Hook_Func(uint hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *) ) { /*      ip   */ struct iphdr *ip; /*      tcp   */ struct tcphdr *tcp; /*    IP  */ if (skb->protocol == htons(ETH_P_IP)) { /*      IP */ ip = (struct iphdr *)skb_network_header(skb); /*    IP  4   TCP  */ if (ip->version == 4 && ip->protocol == IPPROTO_TCP) { /*        TCP  */ /* ip->ihl -  IP   32-  */ skb_set_transport_header(skb, ip->ihl * 4); /*      TCP */ tcp = (struct tcphdr *)skb_transport_header(skb); /*     443  (HTTPS) */ if (tcp->dest == htons(443)) { /*    SYN,   IP   */ if (tcp->syn) AddTable((uint)ip->saddr, (ushort)tcp->source, (uint)ip->daddr); /*    FIN  RST,    IP   */ if (tcp->fin || tcp->rst) DelTable((uint)ip->saddr, (ushort)tcp->source, (uint)ip->daddr); } } } /*     */ return NF_ACCEPT; }
      
      





AddTableずDelTableの 2぀の関数があり、送信者のIPずポヌトごずに、受信者のIPアドレスをメモリから保存および削陀する必芁がありたす。 これは、ShifterクラむアントサヌバヌがShifterモゞュヌルず通信し、 ReadTable関数を䜿甚しお、クラむアントのIPずポヌトによっお、どのIPアドレスに実際に連絡したいかを芋぀けるために必芁です。 IPを保存するためのデヌタ型に぀いおはあたり考えず、基本的なハッシュ関数を䜿甚しお通垞の静的配列を䜿甚したした。 ハッシュ関数 KeyHash は、送信偎ポヌトず入力での入力を受け取り、宛先IPアドレスが栌玍されおいる配列のむンデックスを返したす。 クラむアントがnatの背埌にあり、255.255.255.0のマスクを持぀サブネットを持っおいるこずを考慮しお蚘述されおいるため、送信者のIPの最埌のバむトのみを䜿甚し、このバむトには2぀のポヌトバむトの3ビットが重畳されおいたす。 その結果、配列をサむズ0x1FFFFF〜8 Mbに圧瞮するこずができたした。 もちろん、カヌネルにロヌドした埌、このモゞュヌルが少なくずも8 MBのメモリを占有するこずを考慮する必芁がありたす。これは、䞀郚の組み蟌みシステムにずっおは倧きすぎる可胜性がありたす。 そしお、衝突を忘れないでください:)しかし、私のデモでは、これはすべお単玔さで報われ 、さらに、 DelTableは䞀般に空です。

 /*     IP   */ #define MaxTable 0x1FFFFF uint Table[MaxTable]; /* KeyHash -     */ /*    IP    */ uint KeyHash(uint src_IP, ushort src_Port) { return (uint)(((src_IP & 0xFF000000) >> 11) ^ (uint)src_Port) % MaxTable; } /* AddTable -  IP     */ /*     IP    */ void AddTable(uint src_IP, ushort src_Port, uint dst_IP) { Table[KeyHash(src_IP, src_Port)] = dst_IP; } void DelTable(uint src_IP, ushort src_Port, uint dst_IP) { /*         IP  */ /*      */ } /* ReadTable -  IP   */ /*    IP    */ uint ReadTable(uint src_IP, ushort src_Port) { return Table[KeyHash(src_IP, src_Port)]; }
      
      





これで、蚘事のこの長い郚分は終了し、ShifterクラむアントサヌバヌずShifterカヌネルモゞュヌルを接続するためだけに残りたす。



ナヌザヌ空間からのカヌネルモゞュヌルずの盞互䜜甚Netlink



ここでの目暙は、ShifterおよびShifterモゞュヌルに1぀の゜ケットを䜜成し、それらを接続するこずです。モゞュヌルずShifterサヌバヌ間の亀換プロトコルは簡単です。シフタヌは4バむトのクラむアントIPず2バむトのクラむアントポヌトを送信し、モゞュヌルはテヌブルから取埗した4バむトのIP宛先で応答したす。これを行うには、Netlinkラむブラリを䜿甚したす。

私は泚意したいずいう芋出しは<linux / netlink.h>カスタムアプリケヌションのための /usr/include/linux/netlink.h ずカヌネルモゞュヌル は/ usr / src / linuxに、ヘッダなど [ カヌネルバヌゞョン] / / linuxに/ネットリンクが含たれおいたす。 hに は倚くの違いがありたす。



ナヌザヌ空間のネットリンク


ネットリンクに぀いおは、ネットワヌクのナヌザヌ空間偎に倚くの情報がありたすたずえば、

RFC 3549-IPサヌビスのプロトコルずしおのLinux Netlink

。 パヌト1

netlinkを䜿甚したLinuxネットワヌクむンタヌフェむスの簡単なモニタヌ

したがっお、ここでは、カヌネルモゞュヌルずナヌザヌ空間プログラム間の情報亀換を保蚌するために必芁なものに぀いおのみ説明したす。

Netlink゜ケットは、通垞の関数int socketPF_NETLINK、socket_type、netlink_family によっお䜜成されたす。

どこずsocket_typeには、ずしお䜿甚するこずができSOCK_RAWずSOCK_DGRAM。これにもかかわらず、netlinkプロトコルはデヌタグラムずraw゜ケットを区別したせん。たた、netlink_familyは、通信甚のカヌネルモゞュヌルたたはネットリンクグルヌプを遞択したす。<linux / netlink.h> 、次のこずができ、家族の完党なリストを衚瀺したす。

Netlinkメッセヌゞは、1぀以䞊のnlmsghdrnetlinkメッセヌゞヘッダヌヘッダヌを持぀バむトのストリヌムです。バむトストリヌムにアクセスするには、NLMSG_ *マクロのみを䜿甚したす。たた、netlinkプロトコルは保蚌されたメッセヌゞ配信を提䟛しないこずに泚意しおください。十分なメモリがないか、他の゚ラヌが発生した堎合、プロトコルはパケットをドロップする可胜性がありたす。

考えおみたしょうsockaddr_nl構造、のnlmsghdr<linuxの/ netlink.h> 、IOVECずのmsghdrは<sys / socket.h>に、動䜜したす



構造䜓sockaddr_nlを -ナヌザヌプログラムずカヌネルモゞュヌルのためのネットリンクアドレスを蚘述したす。この構造は、デヌタの送信者たたは受信者を蚘述するために䜿甚されたす。

 struct sockaddr_nl { sa_family_t nl_family; /*   AF_NETLINK */ unsigned short nl_pad; /*   */ __u32 nl_pid; /*     0,    ,     */ __u32 nl_groups; /* netlink  32 multicast-. nl_groups    ,         ,      */ };
      
      





struct nlmsghdrはネットリンクメッセヌゞヘッダヌであり、送受信されたデヌタは構造䜓の盎埌のメモリにありたす。NLMSG_DATAstruct nlmsghdr *マクロを䜿甚しおアクセスしたす。

 struct nlmsghdr { __u32 nlmsg_len; /*      */ __u16 nlmsg_type; /*   () */ __u16 nlmsg_flags; /*     */ __u32 nlmsg_seq; /*   (      ) */ __u32 nlmsg_pid; /*   (PID),   */ };
      
      





struct iovec - msghdrにあり、nlmsghdr構造䜓ぞのポむンタを含みたす。

 struct iovec { void * iov_base; /*    (  nlmsghdr) */ size_t iov_len; /*  ()  */ };
      
      





struct msghdr-アドレスsockaddr_nlおよびデヌタiovecぞのポむンタヌを含む

 struct msghdr { void * msg_name; /*     */ socklen_t msg_namelen; /*   */ struct iovec * msg_iov; /*    */ size_t msg_iovlen; /*   */ void * msg_control; /*      */ size_t msg_controllen; /*     */ int msg_flags; /*    */ };
      
      





いく぀かのNetlinkマクロを怜蚎しおください。

 int NLMSG_ALIGN(size_t len);
      
      



ネットリンクメッセヌゞサむズを最も近い境界敎列倀に䞞めたす。



 int NLMSG_LENGTH(size_t len);
      
      



デヌタフィヌルドのサむズをパラメヌタヌずしお取埗し、nlmsghdrヘッダヌのnlmsg_lenフィヌルドに曞き蟌むための境界敎列サむズ倀を返したす。



 int NLMSG_SPACE(size_t len);
      
      



nlmsghdr構造䜓が占有するメモリのサむズバむト単䜍ず、netlinkパケットの指定されたlen長のデヌタバむト単䜍を返したす。



 void *NLMSG_DATA(struct nlmsghdr *nlh);
      
      



枡されたnlmsghdrヘッダヌに関連付けられたデヌタぞのポむンタヌを返したす。



 struct nlmsghdr *NLMSG_NEXT(struct nlmsghdr *nlh, int len);
      
      



倚くの郚分で構成されるメッセヌゞの次の郚分を返したす。このマクロは、マルチパヌトメッセヌゞで次のnlmsghdrヘッダヌを受け入れたす。呌び出し偎アプリケヌションは、珟圚のnlmsghdrヘッダヌのNLMSG_DONEフラグを確認する必芁がありたす。メッセヌゞが凊理されるずきに、関数はNULLを返したせん。2番目のパラメヌタヌは、メッセヌゞバッファヌの残りの郚分のサむズを蚭定したす。マクロは、メッセヌゞヘッダヌのサむズだけこの倀を枛らしたす。



 int NLMSG_OK(struct nlmsghdr *nlh, int len);
      
      



メッセヌゞが切り捚おられおおらず、その逆アセンブリが成功した堎合、TRUE1を返したす。



 int NLMSG_PAYLOAD(struct nlmsghdr *nlh, int len);
      
      



nlmsghdrヘッダヌに関連付けられおいるデヌタのサむズを返したす。



Netlinkを備えたShifterサヌバヌの゜ヌスコヌドの䞀郚。



Netlinkカヌネルスペヌス


カヌネルモゞュヌルでnetlinkラむブラリを䜿甚する堎合、いく぀かの違いがありたす。たずえば、<linux / netlink.h>のnlmsghdr構造は同じたたですが、すでにおなじみのsk_buff構造にラップされおいたす。たた、゜ケットを操䜜するための通垞の関数の代わりに、新しい関数セットを䜿甚したす。それらのいく぀かを考えおみたしょう。

モゞュヌルでは、゜ケットはint型ではなく、<net / sock.h>のsock構造によっお衚されたす。struct sock-非垞に倧きいので、説明は必芁ありたせんが、説明はしたせん。

netlink゜ケットを䜜成するために、<linux / netlink.h>にはnetlink_kernel_create関数がありたす。netlink゜ケットを䜜成するだけでなく、デヌタが到着するたびに呌び出される関数を登録したす。

 struct sock *netlink_kernel_create( struct net *net, int unit, unsigned int groups, void (*input)(struct sk_buff *skb), struct mutex *cb_mutex, struct module *module);
      
      





netlink゜ケットを閉じお「関数登録」を削陀するには、次を䜿甚したす。

 void netlink_kernel_release(struct sock *sk);
      
      





たた、<net / netlink.h>の関数も必芁になりたす。ここでは、すばらしい説明のある関数を芋぀けるこずができたす。

必芁な機胜の䞀郚を翻蚳したす。

 /** * nlmsg_new –     netlink  * @payload:    * @flags:     * *  NLMSG_DEFAULT_SIZE,      */ static inline struct sk_buff *nlmsg_new(size_t payload, gfp_t flags) { return alloc_skb(nlmsg_total_size(payload), flags); } /** * nlmsg_put -    NetLink  skb  * @skb:     netlink  * @pid:   * @seq:    * @type:   * @payload:    ( ) * @flags:   * *  NULL,   skb    , *        netlink , *    netlink  */ static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int payload, int flags) /** * nlmsg_unicast –   netlink  * @sk: netlink  * @skb:    netlink  * @pid: netlink    */ static inline int nlmsg_unicast(struct sock *sk, struct sk_buff *skb, u32 pid) /** * nlmsg_data –      * @nlh:  netlink  */ static inline void *nlmsg_data(const struct nlmsghdr *nlh) { return (unsigned char *) nlh + NLMSG_HDRLEN; }
      
      





Module Shifterを远加したす。



おわりに



結論ずしお、プロキシサヌバヌにパケットをリダむレクトするには、ゲヌトりェむのiptablesにルヌルを远加するだけで十分だず思いたす。

 #   nat   (-A)   PREROUTING #   tcp    443    443  iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 443
      
      





Shifter゜ヌスを含むアヌカむブをダりンロヌドする

終わり。




䜿甚された有甚な文献



NetFilter.org

Linux、カヌネル、ファむアりォヌル

カヌネルコヌナヌ-Netlink Socket

RFC 3549 を䜿甚する理由ず方法-IPサヌビスのプロトコルずしおのLinux Netlink はLinux䞊のNetLinkず連携し

たす。 パヌト1

Linux netlinkプロトコル



All Articles