EN JA
LIBALIAS(3)
LIBALIAS(3) FreeBSD Library Functions Manual LIBALIAS(3)

名称

libaliasマスカレードとネットワークアドレス変換のためのパケットエイリアスライブラリ

書式

#include < sys/types.h>
#include < netinet/in.h>
#include < alias.h>

関数のプロトタイプは、テキストの本文で与えられます。

解説

libalias ライブラリは、マスカレードとネットワークアドレス変換 (NAT) を対象とした、 IP パケットのエイリアスとデエイリアス (エイリアスの解除) のための関数を集めたものです。

紹介

このライブラリは、IP マスカレードとネットワークアドレス変換の処理過程を支援するように設計された適度に移植性のある関数の集合です。未登録の IP アドレスのローカルネットワークからの発信するパケットは、あたかもそれらがアクセス可能な IP アドレスから来たかのように見えるエイリアスできます。それらがローカルネットワークの正確なマシンに送信されるように、着信パケットは、デエイリアスされます。

ある程度の柔軟性は、パケットエイリアスエンジンのなかに組み込まれています。最も簡単な操作モードにおいて、多対 1 のアドレスマッピングは、ローカルネットワークとパケットエイリアスホストの間で行なわれます。これは、IP マスカレードとして知られています。さらに、ローカルアドレスとパブリックアドレスの間の 1 対 1 のマッピングも実装することができ、それは、静的 NAT として知られています。これらの極端の間では、プライベートアドレスの異なるグループは、いくつかのはっきりと識別できる多対 1 のマッピングを構成する、異なるパブリックアドレスにリンクできます。さらに、与えられたパブリックアドレスとポートは、静的にプライベートアドレス/ポートに転送先を変更できます。

初期化と制御

特別な 1 つの関数、 LibAliasInit() は、すべてのパケット操作が実行される前に、常に呼び出されなければなりません、そして、他のすべての関数へ渡されなければならないポインタのインスタンスを返します。通常 LibAliasSetAddress() 関数は、デフォルトのエイリアスアドレスを設定するために後で呼び出されます。さらに、パケットエイリアスエンジンの操作のモードは、 LibAliasSetMode() を呼び出すことによりカスタマイズできます。

struct libalias * LibAliasInit( struct libalias *)

この関数は、内部データ構造体を初期化するために使用されます。最初に呼び出されたとき、引数として NULL ポインタが渡されるべきです。次のモードビットは、 LibAliasInit() を呼び出した後に常に設定されます。これらのモードビットの意味に関しては、下記の LibAliasSetMode() の記述を参照してください。

  • PKT_ALIAS_SAME_PORTS
  • PKT_ALIAS_USE_SOCKETS
  • PKT_ALIAS_RESET_ON_ADDR_CHANGE

この関数は、同じ初期状態のパケットエイリアスエンジンを常に返します。 LibAliasSetAddress() 関数は、通常後で呼び出され、また、上記のリストされたデフォルトモードビットからのどんな要望された変更は、 LibAliasSetMode() への呼び出しを要求します。

この関数は、必ず任意のパケット操作の前にプログラムの最初で呼び出してください。

void LibAliasUninit( struct libalias *)

この関数は、返り値がなく、内部データ構造体にアタッチされた任意のリソースをクリアするために使用されます。

この関数は、プログラムがエイリアスエンジンの使用を停止されるときに呼び出されるべきです。とりわけ、それは、どんなファイアウォールの穴もきれいに一掃します。後方互換性と特別なセキュリティを提供するために、それは、 LibAliasInit() によって atexit(3) チェーンに追加されます。

void LibAliasSetAddress( struct libalias *, struct in_addr addr)

この関数は、ローカルエリアネットワークから発信するパケットがエイリアスされるソースアドレスを設定します。すべての発信パケットは、 LibAliasRedirectAddr() によって確立された静的アドレスのマッピングによって上書きされなければ、このアドレスへ再マッピングされます。この関数が呼び出されず、静的規則が一致しないなら、発信パケットは、そのソースアドレスを保持します。

PKT_ALIAS_RESET_ON_ADDR_CHANGE モードビット (デフォルトの操作モード) が設定されるなら、内部エイリアスリンクテーブルは、エイリアスアドレスの変更のときは、いつでもリセットされます。これは、IP アドレスが連続するダイヤルアップの試みで変更されるかどうか分からないところで、 ppp(8) のようなインタフェースに便利です。

PKT_ALIAS_RESET_ON_ADDR_CHANGE モードビットが 0 に設定されるなら、(オーバヘッドの少ない呼び出しで) また、パケットからパケット基盤でエイリアスアドレスを動的に変更するために、この関数も使用することができます。

この関数は、必ず任意のパケット操作の前で呼び出してください。

unsigned int LibAliasSetMode( struct libalias *, unsigned int flags, unsigned int mask)

この関数は、 flags の値に従ってモードビットを設定するか、またはクリアします。 mask でマークされたビットだけが影響されます。次のモードビットが < alias.h> に定義されています。
PKT_ALIAS_LOG
/var/log/alias.log へのロギングを可能にします。エイリアスリンクが作成されるか、または削除されるたびに、ログファイルは、ICMP、TCP と UDP リンクの現在の数が追加されます。ログファイルが tail(1) で連続的に見られるとき、主としてデバッグするために役立ちます。
PKT_ALIAS_DENY_INCOMING
このモードビットが設定されるなら、新しい TCP 接続または新しい UDP トランザクションに関連したすべての着信パケットは、呼び出しプログラムによって無視される ( LibAliasIn() は、 PKT_ALIAS_IGNORED コードを返します) ようにマークされます。パケットエイリアスホストまたはローカルネットワークから始められた接続かトランザクションへのレスポンスパケットは、影響されません。このモードビットは、一方向のファイアウォールを実装するために役立ちます。
PKT_ALIAS_SAME_PORTS
このモードビットが設定されるなら、パケットエイリアスエンジンは、実際のローカルポート番号からエイリアスポート番号をそのまま変更しないようにします。これは、5 つ (プロト (proto)、エイリアスアドレス、エイリアスポート、リモートアドレス、リモートポート) がユニークな限り行うことができます。競合が存在するなら、例えば、このモードビットが設定されていても、新しいエイリアスポート番号が選択されます。
PKT_ALIAS_USE_SOCKETS
パケットエイリアスホストがネットワークトラフィックを転送するのと同様にそれを発生するとき、このビットは、設定されるべきです。パケットエイリアスホストが、未知のホストアドレスあるいは未知のポート番号からの接続 (例えば FTP データ接続) を待っているとき、このモードビットは、ポート競合を防ぐためにプレースホルダとしてソケットが割り付けられることを特定します。いったん接続が確立されれば、通常 1 分程度以内でソケットは、クローズされます。
PKT_ALIAS_UNREGISTERED_ONLY
このモードビットが設定されるなら、未登録のアドレス空間から発生しないローカルネットワーク上のトラフィックは、無視されます。標準クラス A、B と C の未登録のアドレスは、次の通りです:

10.0.0.0 -> 10.255.255.255 (クラス A サブネット) 172.16.0.0 -> 172.31.255.255 (クラス B サブネット) 192.168.0.0 -> 192.168.255.255 (クラス C サブネット)

このオプションは、パケットエイリアスホストが異なるインタフェース上のサブネットを登録したか未登録の両方の場合に有用です。登録されたサブネットは、完全に外部の世界へアクセス可能です。したがって、それからのトラフィックは、パケットエイリアスエンジンを通して渡される必要はありません。

PKT_ALIAS_RESET_ON_ADDR_CHANGE
このモードビットが設定され、 LibAliasSetAddress() がエイリアスアドレスを変更するために呼び出されるとき、パケットエイリアスエンジンの内部リンクテーブルは、クリアされます。インタフェースアドレスが時々変更できるか、ダイヤルアップの試みの間で同じのままでありうるところで、この操作モードは、 ppp(8) リンクに役立ちます。このモードビットが設定されないなら、リンクテーブルは、アドレス変更のイベントでリセットされません。
PKT_ALIAS_PUNCH_FW
このオプションは、FTP/IRC DCC 接続のためのファイアウォールをベースとする ipfirewall(4)libalias “パンチホール”を作ります。パンチホールは、IP アドレスとポートから/によって結びつけられます。別の接続のためにホール使用することできません。それを使用する接続が止まるとき、ホールは、取り除けられます。 libalias (例えば、kill -9) を使用してプログラムの予期しない終りを応じることは、フラグの状態の変更によりホールのために割り付けられたすべてのファイアウォール範囲をクリアします。また、このクリアは、このフラグを設定する前に起こらなければならない、 LibAliasSetFWBase() への初期の呼び出しで起こります。
PKT_ALIAS_REVERSE
このオプションは、 libalias が、外部インタフェースではなく内部インタフェースを通して渡されるデータを送り込むことを可能にして、着信パケットと発信パケットを操作する方法を反転させます。
PKT_ALIAS_PROXY_ONLY
このオプションは、 libalias に透過なプロキシ規則だけに従うように命じます。通常のパケットエイリアスは、実行されません。詳細については、下記の LibAliasProxyRule() を参照してください。
PKT_ALIAS_SKIP_GLOBAL
このオプションは、 ipfw_nat によってのみ使用されます。 LibAliasSetMode() へのフラグとして、それを指定することは、効果がありません。その他の詳細については、 ipfw(8) のセクション 「ネットワークアドレス変換 (NETWORK ADDRESS TRANSLATION)」 を参照してください。

void LibAliasSetFWBase( struct libalias *, unsigned int base, unsigned int num)

パンチファイアウォールの穴のために ( PKT_ALIAS_PUNCH_FW フラグで) 割り付けられたファイアウォール範囲を設定します。範囲は、初期化ですべての規則のためにクリアされます。

void LibAliasSkinnyPort( struct libalias *, unsigned int port)

Skinny Station プロトコルによって使用される TCP ポートを設定します。 Skinny は、ボイス IP 呼び出しを設定するために Cisco Call Managers (マネージャ) と通信するために、 Cisco IP 電話によって使用されます。これが設定されないなら、Skinny エイリアスは、行われません。 Skinny によって使用される典型的なポートは、2000 です。

パケット操作

パケット操作関数は、(リモートからローカルへの) 着信パケット、(ローカルからリモートへの) 発信パケットを修正するために使用されます。呼び出しプログラムは、ネットワークインタフェースを介する受信パケットと送信パケットに対して責任があります。

LibAliasInit() と LibAliasSetAddress() とともに、2 つのパケット操作関数 LibAliasIn() と LibAliasOut() は、基本的な IP マスカレードの実装のために必要とされる最低限の一式の関数で構成されています。

int LibAliasIn( struct libalias *, char *buffer, int maxpacketsize)

リモートマシンからローカルネットワークに到達する着信パケットは、この関数によってデエイリアス (de-aliase) されます。 IP パケットは、 buffer によって指されます。また、 maxpacketsize は、パケットを含んでいるデータ構造体のサイズを示し、実際のパケットサイズより少なくとも同じ大きさであるべきです。

返りコードは、次の通りです:

PKT_ALIAS_OK
パケットエイリアス処理は、成功しました。
PKT_ALIAS_IGNORED
パケットは、無視され、デエイリアスされませんでした。プロトコルが認識されないなら、 ICMP メッセージタイプが操作されないか、または新しい接続のための着信パケットが無視されるなら、 ( PKT_ALIAS_DENY_INCOMING モードビットが LibAliasSetMode() を使用して設定されたなら)、これは、起こるかもしれません。
PKT_ALIAS_UNRESOLVED_FRAGMENT
ヘッダフラグメントがまだ送られていないので、フラグメントを解決することができないとき、これは、返されます。この状況で、ヘッダフラグメントが見つかるまで、フラグメントは、 LibAliasSaveFragment() で保存されなければなりません。
PKT_ALIAS_FOUND_HEADER_FRAGMENT
パケットエイリアスプロセスは、成功し、ヘッダフラグメントは、見つかりました。これは、 LibAliasGetFragment() で任意の未解決のフラグメントを検索するシグナルで、 LibAliasFragmentIn() でそれらをデエイリアスします。
PKT_ALIAS_ERROR
パケットエイリアスエンジン内で内部エラーが生じました。

int LibAliasOut( struct libalias *, char *buffer, int maxpacketsize)

ローカルネットワークからリモートマシンへ到達する発信パケットは、この関数によってエイリアスされます。 IP パケットは、 buffer によって指されます。また、 maxpacketsize は、最大のパケットサイズを示し、変更されるパケット長を許容できるべきです。 IP エンコードプロトコルは、修正されなければならず、パケットの長さの変更を明らかにすることができるカプセル化されたデータストリームにアドレスとポート情報を置きます。そのようなプロトコルのよく知られた例は、FTP と IRC DCC です。

返りコードは、次の通りです:

PKT_ALIAS_OK
パケットエイリアス処理は、成功しました。
PKT_ALIAS_IGNORED
パケットは、無視され、エイリアスされませんでした。プロトコルが認識できないか、あるいは ICMP メッセージタイプが操作されないなら、これは、起こるかもしれません。
PKT_ALIAS_ERROR
パケットエイリアスエンジン内で内部エラーが生じました。

ポートとアドレスリダイレクション (出力先変更)

このセクションに記述された関数は、ローカルネットワーク上のマシンが、外部ネットワークからの新しく着信する通信をある程度アクセス可能にすることを許可します。個々のポートは、再マップすることができるか、または静的なネットワークアドレス変換を指定できます。

struct alias_link * LibAliasRedirectPort( struct libalias *, struct in_addr local_addr, u_short local_port, struct in_addr remote_addr, u_short remote_port, struct in_addr alias_addr, u_short alias_port, u_char proto);

この機能は、与えられたリモートアドレス/ポートから指定されたローカルアドレス/ポートへリダイレクトされるエイリアスアドレス/ポートへのトラフィックを明記します。 < netinet/in.h> で定義されるように、パラメータ proto は、 IPPROTO_TCP または IPPROTO_UDP のいずれかを指定できます。

local_addr または alias_addr が 0 であるなら、これは、 LibAliasSetAddress() によって確立されるパケットエイリアスアドレスが使用されることを示します。 LibAliasSetAddress() が LibAliasRedirectPort() が呼ばれた後、アドレスを変更するために呼ばれても、0 参照は、この変更を追跡記録するでしょう。

リンクがロード共有で操作をさらに設定するなら、 local_addrlocal_port は、無視され、下記の LibAliasAddServer() に記述されるように、サーバプールから動的に選択されます。

remote_addr が 0 であるなら、任意のリモートアドレスからのパケットをリダイレクトすることを示します、同様に、 remote_port が 0 であるなら、任意のリモートポート番号から由来するパケットをリダイレクトすることを示します。リモートポート仕様は、ほとんどの場合、0 になりますが、 0 でないリモートアドレスは、ファイアウォールに時々役立つことができます。 LibAliasRedirectPort() への 2 つの呼び出しがそれらのアドレス/ポート仕様で重複するなら、最新の呼び出しが優先されます。

この関数は、 LibAliasRedirectDelete() によって続いて使用することができるポインタを返します。 NULL が返されるなら、関数呼び出しは、成功して終了しませんでした。

すべてのポート番号は、ネットワークアドレスバイト順であるべきです。したがって、これらのパラメータを内部的に判読可能な数値からネットワークバイト順に変換するために htons(3) を使用する必要があります。アドレスもまた struct in_addr データタイプを暗黙で使用するネットワークバイト順です。

struct alias_link * LibAliasRedirectAddr( struct libalias *, struct in_addr local_addr, struct in_addr alias_addr);

この関数は、 alias_addr へのすべての着信トラフィックを local_addr にリダイレクトするように指定します。同様に、 local_addr からのすべての発信トラフィックは、 alias_addr にエイリアスされます。

local_addr または alias_addr が 0 であるなら、これは、 LibAliasSetAddress() によって確立されるパケットエイリアスアドレスが使用されることを示します。 LibAliasSetAddress() が LibAliasRedirectAddr() が呼び出された後にアドレスを変更するために呼び出されても、0 参照は、この変更を追跡記録します。

リンクがロード共有で操作をさらに設定するなら、 local_addr 引数は、無視され、下記の LibAliasAddServer() に記述されるように、サーバプールから動的に選択されます。

LibAliasRedirectAddr() へのその後の呼び出しが同じエイリアスアドレスを使用するなら、エイリアスアドレスへのすべての新しい着信トラフィックは、最後の関数呼び出しで作られたローカルアドレスへリダイレクトします。いくつかの関数呼び出しで指定された、ローカルマシンのいずれかによって生成された新しいトラフィックは、同じアドレスへエイリアスされます。次の例を考慮してください。

LibAliasRedirectAddr(la, inet_aton("192.168.0.2"),
inet_aton("141.221.254.101")); LibAliasRedirectAddr(la, inet_aton("192.168.0.3"),
inet_aton("141.221.254.101")); LibAliasRedirectAddr(la, inet_aton("192.168.0.4"),
inet_aton("141.221.254.101"));

192.168.0.2、192.168.0.3 と 192.168.0.4 からの telnet(1) または ftp(1) のようなどんな発信の接続も、141.221.254.101 から来るように見えます。 141.221.254.101 までどんな着信接続も 192.168.0.4 にリダイレクトされます。

LibAliasRedirectPort() へのどんな呼び出しも、 LibAliasRedirectAddr() によって指定されたアドレスマッピングより優位になります。

この関数は、 LibAliasRedirectDelete() によってそれ以降使用することができるポインタを返します。 NULL が返されるなら、関数呼び出しは、成功して終了しませんでした。

int LibAliasAddServer( struct libalias *, struct alias_link *link, struct in_addr addr, u_short port);

この関数は、 IP Network Address Translation (RFC 2391, LSNAT) を使用して、ロード共有のために link (リンク) を設定します。 LSNAT は、次のように動作します。クライアントは、サーバ仮想アドレスの使用によりサーバをアクセスすることを試みます。 LSNAT ルータは、実時間 (リアルタイム) のロード共有アルゴリズムを使用して、サーバプール中のホストの 1 つに対して要求を透過的にリダイレクトします。複数のセッションは、同じクライアントから開始され、セッションが開始されるとき、サーバプールホストを越えてロードバランスに基づく異なるホストに各セッションを向けることができます。ロード共有がわずかの特定のサービスに対して要求されるなら、 LSNAT の設定は、単に要求されたサービスへのロード共有を制限するために定義できます。

現在、ホストがホストのロードに配慮をせずにラウンドロビン原理のみで選択されている場合に、最も単純な選択アルゴリズムだけが実装されています。

最初に、 link は、 LibAliasRedirectPort() または LibAliasRedirectAddr() のいずれかによって作成されます。次に、 LibAliasAddServer() は、 link のサーバプールへのエントリを加えるために複数回呼び出されます。

LibAliasRedirectAddr() で作成されたリンクについては、 port 引数は、無視され、どんな値、例えば htons(~0) もありえます。

この関数は、成功すれば 0 を返し、そうでなければ-1 を返します。

int LibAliasRedirectDynamic( struct libalias *, struct alias_link *link)

この関数は、動的に LibAliasRedirectPort() によって入力された、指定された静的なリダイレクト規則をマークします。規則が削除された後、動的に単一の TCP 接続をリダイレクトするような例でこれは、使用できます。完全に指定されたリンクだけが動的になることができます。 (静的対動的、および部分的対完全に指定されたリンクの定義については、下記の 「静的と動的リンク」「部分的に指定されたエイリアスリンク」 を参照してください。)

この関数は、成功すれば 0 を返し、そうでなければ-1 を返します。

void LibAliasRedirectDelete( struct libalias *, struct alias_link *link)

この関数は、 LibAliasRedirectPort() か LibAliasRedirectAddr() によって入力された指定された静的リダイレクト規則を削除します。パラメータ link は、リダイレクション関数のどちらかによって返されたポインタです。無効のポインタが LibAliasRedirectDelete(), に渡されるなら、プログラムクラッシュか、または予測できない結果となるので、この関数を使用するとき、注意が必要です。

int LibAliasProxyRule( struct libalias *, const char *cmd)

渡された cmd 文字列は、1 つ以上の語のペアからなります。各組の最初の語は、トークンで、2 番目は、そのトークンのために適用されるべき値です。トークンとそれらの引数タイプは、次の通りです:
type encode_ip_hdr | encode_tcp_stream | no_encode
透過なプロキシをサポートするために、新しい宛先サーバへ元のアドレスとポート情報を何らかの形で渡すことは必要です。 encode_ip_hdr が指定されるなら、元の宛先アドレスとポートは、特別の IP オプションとして渡されます。 encode_tcp_stream が指定されるなら、元の宛先アドレスとポートは、フォーマット“ DEST IP port”での TCP ストリームのデータの最初の断片として渡されます。
port portnum
宛先ポート portnum のパケットだけがプロキシ処理されます。
server host[ : portnum]
これは、データがリダイレクトされる hostportnum を指定します。 host は、DNS ホスト名ではなく IP アドレスでなければなりません。 portnum が指定されないなら、宛先ポート番号は、変更されません。

delete コマンドが使用されない限り、 server 指定は、強制的です。

rule index
通常は、 LibAliasProxyRule() への各呼び出しは、規則の線形のリストの最初に次の規則を挿入します。 index が指定されるなら、新しい規則は、より低いインデックスですべての規則の後にチェックされます。規則が指定されない LibAliasProxyRule() への呼び出しは、ルール 0 が割り当てられます。
delete index
このトークンとその引数は、他のトークンと共に使用されてはなりません。使用されたとき、与えられた index のすべての既存の規則が削除されます。
proto tcp | udp
指定されれば、与えられたプロトコルタイプのパケットだけが一致します。
src IP[ / bits]
指定されれば、与えられた IP と一致するソースアドレスのパケットだけが一致します。 bits も指定されるなら、 IP の最初の bits ビットは、ネットワーク指定として得られ、そのネットワークからのすべての IP アドレスは、一致します。
dst IP[ / bits]
指定されれば、与えられた IP と一致する宛先アドレスのパケットだけが一致します。 bits も指定されるなら、 IP の最初の bits ビットは、ネットワーク指定として得られ、そのネットワークからのすべの IP アドレスは、一致します。

この関数は、ある種のインターネットアクセスを許されない、内部マシンのための発信の接続をリダイレクトするか、または特定の外部マシンへのアクセスを制限するために通常使用されます。

struct alias_link * LibAliasRedirectProto( struct libalias *, struct in_addr local_addr, struct in_addr remote_addr, struct in_addr alias_addr, u_char proto);

この関数は、与えられたリモートアドレスからエイリアスアドレスへの proto プロトコル番号でどんな IP パケットも指定されたローカルアドレスへリダイレクトされることを指示します。

local_addr または alias_addr が 0 であるなら、これは、 LibAliasSetAddress() によって確立されるパケットエイリアスアドレスが使用されることを示します。 LibAliasSetAddress() が LibAliasRedirectProto() が呼び出された後に、アドレスを変更するために呼び出されても、0 参照は、この変更を追跡記録します。

remote_addr が 0 であるなら、これは、任意のリモートアドレスからのパケットをリダイレクトすることを示します。 0 でないリモートアドレスは、ファイアウォールに時々役立ちます。

LibAliasRedirectProto() への 2 つの呼び出しがそれらのアドレス指定でオーバラップするなら、最新の呼び出しが優先します。

この関数は、 LibAliasRedirectDelete() によって続いて使用することができるポインタを返します。 NULL が返されるなら、関数呼び出しは、成功して終了しませんでした。

フラグメント操作

このセクションの関数は、着信フラグメントを処理するために使用されます。

発信フラブメントは、 LibAliasRedirectAddr() によって設定された任意の適用可能なマッピングによってアドレスを変更することにより、または LibAliasSetAddress() によって設定されたデフォルトエイリアスアドレスにより、 LibAliasOut() で操作されます。

着信フラグメントは、2 つの方法のうちの 1 つで処理されます。フラグメント IP パケットのヘッダが既に見られたなら、後のフラグメントは、すべてヘッダフラグメントと同じ方法で再マッピングされます。ヘッダの前に到着するフラグメントは、保存され、いったんヘッダフラグメントが解決されたならば取り出されます。

int LibAliasSaveFragment( struct libalias *, char *ptr)

LibAliasIn() が PKT_ALIAS_UNRESOLVED_FRAGMENT を返すなら、この関数は、未決着のフラグメントへのポインタを保存するために使用できます。

ptr は、 malloc(3) によって割り付けられたメモリのブロックを指すことが暗黙に仮定されています。フラグメントが解決されないなら、パケットエイリアスエンジンは、タイムアウト時間経過後に自動的にメモリを解放します。 [いつかは、メモリを解放するためのコールバック関数が引数として渡されるように、この関数は、修正されるべきです。]

この関数は、それが成功したなら、 PKT_ALIAS_OK を返し、エラーがあった場合は、 PKT_ALIAS_ERROR を返します。

char * LibAliasGetFragment( struct libalias *, char *buffer)

この関数は、 LibAliasSaveFragment() によって保存されたフラグメントポインタを取り出すために使用できます。 buffer によって指される IP ヘッダフラグメントは、 LibAliasIn() が PKT_ALIAS_FOUND_HEADER_FRAGMENT を返すときに示されたヘッダフラグメントです。いったんフラグメントポインタが取り出されると、それは、フラグメントに対するダイナミックに割り付けられたメモリを解放することは呼び出しプログラムの責任になります。

これ以上利用可能なフラグメントがなくなるまで、 LibAliasGetFragment() 関数は、連続して呼び出すことができます。フラグメントがなくなったときに、それは、 NULL を返します。

void LibAliasFragmentIn( struct libalias *, char *header, char *fragment)

フラグメントが LibAliasGetFragment() で取り出されるとき、それは、 LibAliasFragmentIn() への呼び出しでデエイリアスできます。 header 引数は、テンプレートとして使用されるヘッダフラグメントへのポインタです。そして、 fragment は、デエイリアスされるパケットへのポインタです。

雑多な関数

struct alias_link * AddLink( struct libalias *, struct in_addr src_addr, struct in_addr dst_addr, struct in_addr alias_addr, u_short src_port, u_short dst_port, int alias_param, int link_type)

この関数は、新しい状態をインスタンスのハッシュテーブルに追加します。 dst_address そして/または dst_port は、 LibAliasSetAddress が使用されたアドレスを変更することができるので、いくつかの動的な文字をリンクに取り入れる、0 として与えられます。しかしながら、現在の実装では、着信 (ext -> int) トラフィックのためにそのようなリンクのみを使用することができます。

void LibAliasSetTarget( struct libalias *, struct in_addr addr)

着信パケットが、ホストマシンに到着する任意の既存のエイリアスリンクに関連しなかったとき、それは、 LibAliasSetTarget() への呼び出しによって示されたアドレスへ送られます。

この関数が INADDR_NONE アドレス引数で呼び出されるなら、すべての新しい着信パケットは、 LibAliasSetAddress() によって設定されたアドレスへ行きます。

この関数が呼び出されないか、 INADDR_ANY アドレス引数で呼び出されるなら、すべての新しい着信パケットは、パケットで指定されたアドレスへ行きます。それらが問題のマシンへのパケットを送ることができるなら、外部マシンが内部マシンに直接話すことを可能にします。

int LibAliasCheckNewLink( struct libalias *)

新しいエイリアスリンクが作成されたとき、この関数は、0 でない値を返します。着信トラフィックが異なるローカルサーバへ連続して送られている状況で、この関数は、 LibAliasSetTarget() がデフォルトターゲットアドレスを変更するために呼び出される場合に、トリガのために使用できます。

u_short LibAliasInternetChecksum( struct libalias *, u_short *buffer, int nbytes)

これは、他のところで利用可能に思われず、便利なものとして含まれているユーティリティ関数です。 IP とプロトコル (TCP、UDP、ICMP) に特有のヘッダの両方で使用されるインターネットチェックサムを計算します。

buffer 引数は、チェックサムを計算したデータブロックを指します。また、 nbytes は、バイト数です。 16 ビットのチェックサムフィールドは、チェックサムを計算する前に 0 にされるべきです。

また、チェックサムは、そのチェックサムを含むデータブロックで操作することにより検証できます。チェックサムが有効な場合、 LibAliasInternetChecksum() は、0 を返します。

int LibAliasUnaliasOut( struct libalias *, char *buffer, int maxpacketsize)

既にエイリアスされた発信パケットは、この関数によってそのプライベートアドレス/ポート情報を復元します。 IP パケットは、 buffer によって指されます。また、 maxpacketsize は、エラーチェックのために提供されます。既にエイリアスされたパケットがさらなる処理 (例えば、ロギング) のためにそのオリジナルの IP ヘッダを復元する必要があるなら、この関数を使用できます。

概念の背景

このセクションは、ソースコードを修正するかパケットエイリアス関数を使用して、多少難解なアプリケーションを作成したいことを計画している人々を対象にしています。

パケットエイリアスエンジン操作の概念のフレームワークは、ここに記述されます。議論の中心となるのは、ローカルマシン、エイリアスされた識別子とリモートマシン間の与えられたパケットトランザクションのための関係について記述する、 "エイリアスリンク"についての考えです。そのようなリンクがどのように発生するか、破棄されるかが検討されます。

エイリアスリンク

特定の変換を記述する 7 つの要素からなる "エイリアスリンク"についての概念があります。

(ローカルアドレス、ローカルポート、エイリアスアドレス、 
 エイリアスポート、リモートアドレス、リモートポート、プロトコル)

発信パケットは、ローカルアドレスとポート番号がエイリアスアドレスとポート番号で置き換えられます。着信パケットは、逆のプロセスを受けます。パケットエイリアスエンジンは、与えられた IP パケットを修正する方法を決定するためにエイリアスリンクの内部テーブルとパケットを適合させることを試みます。必要なときに、IP ヘッダとプロトコルに依存するヘッダの両方が修正されます。エイリアスリンクは、ネットワークトラフィックによって必要なときに作成され削除されます。

プロトコルは、ある状況で TCP、UDP か ICMP などでありえます。 (一種の ICMP パケットは、どのように個々のパケットを操作すべきかを識別するための等価なポート番号の役割をするシーケンスか ID 番号によってエイリアスできます。)

それぞれのエイリアスリンクは、次の 5 つの数値の組合せを持っていなければなりません。各エイリアスリンクは、次の 5 つの数量のユニークな組み合わせを持っていなければなりません。エイリアスアドレス/ポート、リモートアドレス/ポートとプロトコル。これは、ローカルネットワーク上のいくつかのマシンが同じエイリアス IP アドレスを共有できることを保証します。競合が発生するかもしれない場合には、独自性が維持されるように、エイリアスポートは、選択されます。

静的と動的リンク

エイリアスリンクは、静的であるか動的であるかもしれません。静的リンクは、無期限に持続し、IP パケットの変換のために固定規則を表わします。動的リンクは、特定の TCP 接続や UDP トランザクションか ICMP ECHO シーケンスのために出現します。 TCP の場合については、接続は、関連するエイリアスリンクをいつ削除すべきか知るためにモニタできます。 UDP トランザクション (と ICMP ECHO と TIMESTAMP 要求) のためのエイリアスリンクは、単純なタイムアウト規則で動作します。一定の時間で動的リンク上でアクティビティが観察されないとき、それは、自動的に削除されます。さらに、タイムアウト規則は、適切にオープンかクローズしない TCP 接続に適用されます。

部分的に指定されたエイリアスリンク

エイリアスリンクは、リモートアドレスおよび (または) リモートポートが未知であることを意味する部分的な指定ができます。この場合、不完全な指定と一致するパケットが見つかるとき、完全に指定された動的リンクが作成されます。元の部分的に指定されたリンクが動的であるなら、完全に指定されたリンクが作成された後に削除され、そうでなければそれは、持続されます。

例えば、部分的に指定されたリンクは、次のようになります。

(192.168.0.4, 23, 204.228.203.215, 8066, 0, 0, tcp)

0 は、リモートアドレスとポートのための無指定の構成要素を表します。このリンクが静的な場合、204.228.203.215 のポート 8066 からローカルネットワーク上のマシン 192.168.0.4 のポート 23 (telnet) へすべての着信トラフィックをリダイレクトする効果があります。各個々の telnet (テルネット) 接続は、別個の動的リンクの作成を開始します。

動的リンクの作成

エイリアスリンクすることに加えて、さらにパケットエイリアスメカニズムの内部データテーブルに格納することができるアドレスマッピングがあります。

(ローカルアドレス、エイリアスアドレス)

アドレスマッピングは、新しい動的リンクを作成するときに検索されます。

ローカルネットワークからのすべての発信パケットが既に存在する完全に指定されたリンクと一致しないなら、それらは、自動的に動的リンクを作成します。発信パケットのためのアドレスマッピングが存在するなら、これは、使用されるエイリアスアドレスを決定します。マッピングが存在しないなら、通常デフォルトアドレスとしてパケットエイリアスホストのアドレスが使用されます。必要な場合、このデフォルトアドレスは、各個々のパケットが到着するたびごとに変更できます。

エイリアスポート番号は、新しい動的リンクが任意の存在のリンクと競合しないように決定します。デフォルト操作モードでは、パケットエイリアスエンジンは、ローカルポート番号と等しいエイリアスパケットを設定することを試みます。この結果が競合するなら、ユニークなエイリアスリンクを確立することができるまで、ポート番号は、ランダムに選択されます。代替の操作モードでは、エイリアスポートの最初選択は、ランダムでローカルポート番号と無関係です。

モジュールのアーキテクチャ (と ipfw(4) Sh サポート)

libalias の最新の改良の 1 つは、実行時に新しいプロトコルのサポートをロード/アンロードする能力を与える、新しいプロトコルのサポートをライブラリの残りから独立することです。この機能を達成するために、プロトコル取り扱いのためのすべてのコードは、メインライブラリの外の一連のモジュールに移動されました。これらのモジュールは、同じソースからコンパイルされますが、それらは、カーネルの中、またはユーザランドライブラリの一部として動作するようにコンパイルされるかどうかによって、異なった方法で動作します。

カーネルランドの LIBALIAS モジュール

カーネルのためにコンパイルされるとき、 libalias モジュールは、 alias_ 接頭辞で認識可能な単純な KLD です。

新しいプロトコルのサポートを追加するためには、対応するモジュールをロードします。例えば:

kldload alias_ftp

プロトコルのサポートがもはや必要でないときに、モジュールをアンロードすることができます:

kldunload alias_ftp

ユーザランドの LIBALIAS モジュール

カーネルとユーザランド (KLD メカニズムがない、多くの異なったアドレス空間など) の違いのため、我々は、ユーザランドに、ロードする/追跡する/アンロードするモジュールを扱う方法を少し変更しなければなりませんでした。

ユーザランドの libalias のコンパイルでは、すべてのモジュールは、単純なライブラリで、 /usr/lib に存在し、 libalias_ 接頭辞をつけて認識可能です。

(デフォルトで) 次の内容である設定ファイル /etc/libalias.conf があります:

/usr/lib/libalias_cuseeme.so 
/usr/lib/libalias_ftp.so 
/usr/lib/libalias_irc.so 
/usr/lib/libalias_nbt.so 
/usr/lib/libalias_pptp.so 
/usr/lib/libalias_skinny.so 
/usr/lib/libalias_smedia.so

このファイルは、 libalias がロードするモジュールのパスを含んでいます。新しいモジュールをロード/アンロードするためには、単にパスを libalias.conf に追加し、プログラムから LibAliasRefreshModules() を呼び出します。万一、アプリケーションが SIGHUP シグナルハンドラを提供する場合には、ハンドラの内側で LibAliasRefreshModules() への呼び出しを追加し、ロードされたモジュールをリフレッシュするたびに、 SIGHUP シグナルをそれに送ります:

kill -HUP <process_pid>

モジュールのアーキテクチャ: どのように動作するか

libalias のモジュールアーキテクチャは、実行がカーネルの内側であろうとユーザランドの内側であろうと同様に動作します。 alias_mod.c では、次の通りです:

/* プロトコルとユーザランドモジュールハンドラのチェーン. */ 
LIST_HEAD(handler_chain, proto_handler) handler_chain ... 
... 
SLIST_HEAD(dll_chain, dll) dll_chain ...

handler_chain は、ロードされたすべてのプロトコルハンドラの経過を追い、一方 ddl_chain は、どのユーザランドモジュールがロードされているかを追跡します。

handler_chain は、 struct proto_handler エントリから成ります:

struct proto_handler { 
 u_int pri; 
 int16_t dir; 
 uint8_t proto; 
 int (*fingerprint)(struct libalias *la, 
   struct ip *pip, struct alias_data *ah); 
 int (*protohandler)(struct libalias *la, 
   struct ip *pip, struct alias_data *ah); 
 LIST_ENTRY(proto_handler) entries; 
};

ここで:

pri
は、プロトコルハンドラに割り当てられた優先順位であり、低い優先順位が、より良いです。
dir
は、パケットの方向です: 入って来るもの、または出て行くものです。
proto
は、このパケットがどのプロトコルに属するかを示します: IP、TCP または UDP です。
fingerprint
は、指紋関数を指し、一方、protohandler は、プロトコルハンドラ関数を指します。

fingerprint 関数には、着信パケットが見つけられるか、このモジュールが扱うことができる任意のカテゴリに属すかどうかチェックする二重の役割があります。

protohandler 関数は、 libalias が正しくそれを NAT するように、実際にパケットを操作します。

パケットが libalias に入るとき、モジュールフックに出会うなら、 handler_chain は、パケットのこのタイプにマッチするハンドラがあるかどうか調べるために (それは、パケットのプロトコルと方向をチェックします) 検索されます。次に 1 つ以上のハンドラが見つけられるなら、最も低い優先順位番号でモジュールから始めます。それは、 fingerprint 関数を呼び出して、結果を解釈します。

結果の値が 0 と等しいなら、このハンドラのプロトコルハンドラを呼び出して返ります。そうでなければ、 handler_chain が使い尽くされるまで、次の適任のモジュールへ続きます。

libalias の中では、モジュールフックは、次に似ています:

struct alias_data ad = { 
 lnk, 
 &original_address, 
 &alias_address, 
 &alias_port, 
 &ud->uh_sport,          /* 元の発信元ポート */ 
 &ud->uh_dport,  /* 元の宛先ポート */ 
 256                     /* 最大パケットサイズ */ 
}; 
 
... 
 
/* チェーンを出る */ 
err = find_handler(IN, UDP, la, pip, &ad);

ジュールの役に立つすべてのデータは、 alias_data 構造に集められて、次に、 find_handler() が呼び出されます。 find_handler() 関数は、ハンドラのチェーンを出て行くことに責任があります: それは、入力パラメータとして受信します:

IN
方向
UDP
動作するプロトコル
la
libalias のこのインスタンスへのポインタ
pip
struct ip へのポインタ
ad
struct alias_data (上記参照) へのポインタ

この場合、 find_handler() は、INcoming UDP パケットをサポートのために登録されたモジュールだけを検索します。

前述のように、ユーザランドの libalias は、少し異なっていて、 (モジュールの重複するロード避けて、同じ名前のモジュールを避けて、等) 同様に、モジュールの操作で注意が払われなければならないので、 dll_chain が導入されました。

dll_chain は、ロードされたすべてのユーザランドの libalias モジュールのリストを含んでいます。

アプリケーションが LibAliasRefreshModules() を呼び出すとき、 libalias は、最初にロードされたすべてのモジュールをアンロードし、 /etc/libalias.conf にリストされたすべてのモジュールを再ロードします: ロードされたあらゆるモジュールに関して、新しいエントリは、 dll_chain に追加されます。

dll_chain は、 struct dll エントリから成ります:

struct dll { 
 /* モジュールの名前 */ 
 char            name[DLL_LEN]; 
 /* 
         * dlopen() を通して取得された共有オブジェクトへの 
         * ポインタ - dlsym() を通してロードされたモジュール 
         * から任意のシンボルにアクセスするためにこの 
         * ポインタを使用します 
  */ 
 void            *handle; 
 struct dll      *next; 
};
name
は、モジュールの名前です。
handle
は、 dlopen(3) を通して得られたモジュールへのポインタです。

モジュールがユーザランドでロードされるときはいつでも、エントリは、 dll_chain に追加され、すべてのプロトコルハンドラは、モジュールが、 handler_chain で解決され、登録される点において、存在します。

LIBALIAS のためにどのようにモジュールを書くか

今後の作業の骸骨として使用することができる、 libalias に ( alias_dummy.[ch] と呼ばれる) モジュールがあります。ここで、私たちは、そのモジュールのいくつかの部分を解析します。 alias_dummy.c から:

struct proto_handler handlers [] = {{666, IN|OUT, UDP|TCP, 
        &fingerprint, &protohandler}};

変数 handlers は、存在するハンドラを説明して、不透明な方法で外の世界でそれを使用させるので、モジュールの中で“最も重要なもの”です。

それは、あらゆるモジュールで「常に」存在していなければならなくて、名前 handlers 保有していなければ「なりません」、そうでなければ、ユーザランドのモジュールをロードすることを試みると、不足しているシンボルに関して失敗してエラーを出します: モジュールのロード/アンロードに関する詳しい情報について、 alias.cLibAliasRefreshModules(), LibAliasLoadModule() と LibAliasUnloadModule() を参照してください。

handlers は、モジュールに存在するすべての proto_handler 構造体を含みます。

static int 
mod_handler(module_t mod, int type, void *data) 
{ 
 int error; 
 
 switch (type) { 
 case MOD_LOAD: 
  error = 0; 
  attach_handlers(handlers); 
  break; 
 case MOD_UNLOAD: 
  error = 0; 
  detach_handlers(handlers; 
  break; 
 default: 
  error = EINVAL; 
 } 
 return (error); 
}

KLD として実行するとき、 mod_handler() は、それぞれ attach_handlers() と detach_handlers() を使用してモジュールを登録/登録取り消しをします。

あらゆるモジュールは、少なくとも次の 2 つの関数を含まなければなりません: 1 つは、指紋関数とプロトコルハンドラ関数です。

#ifdef _KERNEL 
static 
#endif 
int 
fingerprint(struct libalias *la, struct ip *pip, struct alias_data *ah) 
{ 
 
... 
} 
 
#ifdef _KERNEL 
static 
#endif 
int 
protohandler(struct libalias *la, struct ip *pip, 
             struct alias_data *ah) 
{ 
 
... 
}

そして、それらは、正確にこれらの入力パラメータを受け付けなければなりません。

ユーザランド LIBALIAS モジュールためのアプリケーションにパッチする

libalias を使用するアプリケーションにモジュールのサポートを追加するために、次の簡単な処置に従うことができます。
  1. アプリケーションのメインファイルを見つけます (それを main.c と呼びます)。
  2. まだ存在しないなら、 main.c のヘッダ部分にこれを追加します:

    #include <signal.h>

    そして、これは、ヘッダ部分の直後です:

    static void signal_handler(int);
  3. アプリケーションの初期化関数に次の行を追加するか、または初期化関数がないなら、 main() にそれを置きます:

    signal(SIGHUP, signal_handler);

    そして、 signal_handler() 関数を main.c のどこかに置きます:

    static void 
    signal_handler(int sig) 
    { 
     
     LibAliasRefreshModules(); 
    }

    そうでなければ、アプリケーションが、既に SIGHUP シグナルを捕らえているなら、シグナルハンドラ関数で LibAliasRefreshModules() への呼び出しを単に追加します。

例えば、 libalias モジュールを使用するために natd(8) をパッチするためには、単に RefreshAddr( int sig __unused) に次の行を追加します:

LibAliasRefreshModules()

再コンパイルすれば、終りです。

カーネルランドでログ記録のサポート

KLD として動作しているとき、 libalias には、現在 ( alias_local.h から) struct libalias の中の割り付けられたバッファで起こるログ記録サポートがあります:

struct libalias { 
       ... 
 
 /* log 記述子        */ 
#ifdef KERNEL_LOG 
 char           *logDesc;        /* 
      * libalias が kld として動作する 
      * とき、自動的的に malloc された 
      * メモリバッファへのポインタ 
      */ 
#else 
 FILE           *logDesc; /* 
      * libalias がユーザランドの lib 
      * として実行するとき、 
      * /var/log/alias.log へのポインタ 
      */ 
#endif 
 
 ... 
}

したがって、 libalias を使用するすべてのアプリケーションは、それらが、 logDesc にアクセスすることを望んでいるなら、それら自体のログを取り扱うことができます。さらに、ログバッファへのあらゆる変更は、 LOG_SECURITY 機能と LOG_INFO レベルで自動的に syslog(3) に追加されます。

作者

Charles Mott <cm@linktel.net>, versions 1.0 - 1.8, 2.0 - 2.4。 Eivind Eklund <eivind@FreeBSD.org>, versions 1.8b, 1.9 と 2.5。多くのアーキテクチャの改良に貢献すると同様に IRC DCC サポートを追加しました。 FTP/IRC DCC のためのファイアウォールバイパスを追加しました。 Erik Salander <erik@whistle.com>は、PPTP と RTSP のサポートを追加しました。 Junichi Satoh <junichi@junichi.org>は、RTSP/PNA のサポートを追加しました。 Ruslan Ermilov <ru@FreeBSD.org>は、一般的なハッキングと同様に PPTP と LSNAT のサポートを追加しました。 Gleb Smirnoff <glebius@FreeBSD.org>は、カーネル空間へライブラリを移植しました。 Paolo Pisati <piso@FreeBSD.org>は、すべてのプロトコル (IP、TCP と UDP を除いた) のサポートを外部のモジュールに移動して、ライブラリモジュールを作成しました。

謝辞

次は、おおよその年代順に、価値のあるコメントや/またはデバッグ援助を提供した個人のリストです。

Gary Roberts Tom Torrance Reto Burkhalter Martin Renters Brian Somers Paul Traina Ari Suutari Dave Remien J. Fortes Andrzej Bialecki Gordon Burditt
July 4, 2011 FreeBSD