Asutorufaのブログ

こんにちは

UDPプロキシはFullcone NATを実現する

投稿日 2024-11-18|更新日: 2024-11-18|カテゴリ Network

NATの種類

Mappingの種類

マッピングはNAT内部から外部にパケットを送信時にアドレス変換する行為です。

  • Endpoint-Independent Mapping

NAT内部のネットワークの同じIPアドレスとポートで外部のそれぞれのUDPサーバ(IPアドレスとポートが違う)にパケットを送信すると、各個UDPサーバも同じIPアドレスとポートのパケットを受信する。
例えば:

送信元アドレス 宛先アドレス NATマッピングアドレス
192.168.1.1:3000 1.1.1.1:3000 43.124.222.234:4500
192.168.1.1:3000 1.1.1.1:3001 43.124.222.234:4500
192.168.1.1:3000 1.1.1.3:3002 43.124.222.234:4500
192.168.1.1:3000 1.1.1.4:3004 43.124.222.234:4500
  • Address-Dependent Mapping

UDPサーバのアドレスが同じ(ポートが違う)なら受信したパケットのIPアドレスとポートを変換しない、そうしないと、IPアドレスやポートを変換する。
例えば:

送信元アドレス 宛先アドレス NATマッピングアドレス
192.168.1.1:3000 1.1.1.1:3000 43.124.222.234:4500
192.168.1.1:3000 1.1.1.1:3001 43.124.222.234:4500
192.168.1.1:3000 1.1.1.2:3000 43.124.222.234:4501
192.168.1.1:3000 1.1.1.3:3003 43.124.222.234:4502
  • Address and Port-Dependent Mapping

UDPサーバのアドレスとポートが同じなら受信したパケットのIPアドレスとポートを変換しない、そうしないと、IPアドレスやポートを変換する。

例えば:

送信元アドレス 宛先アドレス NATマッピングアドレス
192.168.1.1:3000 1.1.1.1:3000 43.124.222.234:4500
192.168.1.1:3000 1.1.1.1:3000 43.124.222.234:4500
192.168.1.1:3000 1.1.1.1:3001 43.124.222.234:4501
192.168.1.1:3000 1.1.1.2:3000 43.124.222.234:4502
192.168.1.1:3000 1.1.1.3:3003 43.124.222.234:4503

Filteringの種類

フィルタリングはNAT外部から内部に送信するパケットをフィルタリングする行為です。

  • Endpoint-Independent Filtering

一旦内部アドレスを外部にマッピングすると、全ての外部サーバから内部に送信することが可能です。
例えば:

内部アドレス マッピング
192.168.1.1:3000 43.124.222.234:4500
送信元アドレス 宛先アドレス 受信する?
1.1.1.1:3000 43.124.222.234:4500 はい 🟢
1.1.1.1:3001 43.124.222.234:4500 はい 🟢
1.1.1.2:3000 43.124.222.234:4500 はい 🟢
1.1.1.3:3002 43.124.222.234:4500 はい 🟢
  • Address-Dependent Filtering

内部から外部に送信したサーバ、且つアドレスも同じなら、サーバから内部に送信することが可能です。
例えば:

内部アドレス マッピング 送信歴史 宛先アドレス
192.168.1.1:3000 43.124.222.234:4500 1.1.1.1:3000
送信元アドレス 宛先アドレス 受信する?
1.1.1.1:3000 43.124.222.234:4500 はい 🟢
1.1.1.1:3001 43.124.222.234:4500 はい 🟢
1.1.1.2:3000 43.124.222.234:4500 ダメ ❌
1.1.1.3:3002 43.124.222.234:4500 ダメ ❌
  • Address and Port-Dependent Filtering

内部から外部に送信したサーバ、且つアドレスとポートも同じなら、サーバから内部に送信することが可能です。

例えば:

内部アドレス マッピング 送信歴史 宛先アドレス
192.168.1.1:3000 43.124.222.234:4500 1.1.1.1:3000
送信元アドレス 宛先アドレス 受信する?
1.1.1.1:3000 43.124.222.234:4500 はい 🟢
1.1.1.1:3001 43.124.222.234:4500 ダメ ❌
1.1.1.2:3000 43.124.222.234:4500 ダメ ❌
1.1.1.3:3002 43.124.222.234:4500 ダメ ❌

Fullcone NAT

Fullcone NATはEndpoint-Independent FilteringとEndpoint-Independent Mappingです。

goで実現する

最も重要なのはNATテーブルの実現です。

// NATテーブル// キーはプロキシクライアントの送信元アドレス// 値はマッピングしたUDPサーバnatTable := map[string]net.PacketConn{} getTargetAddress := func([]byte) (*net.UDPAddr, []byte) {	// TODO implement proxy protocol	return nil, nil} packetResponse := func(net.Addr, []byte) []byte {	// TODO implement proxy protocol	return nil} // mockのUDPプロキシサーバpc, err := net.ListenPacket("udp", "")if err != nil {	panic(err)}defer pc.Close() for {	// IPプロトコルによってパケット最大は65535です。	buf := make([]byte, 65535)	n, addr, err := pc.ReadFrom(buf)	if err != nil {		panic(err)	} 	// クライアントのアドレスでマッピングサーバを保存して	conn, ok := natTable[addr.String()]	if !ok {		// マッピングサーバを作ります		conn, err = net.ListenPacket("udp", "")		if err != nil {			panic(err)		} 		go func() {			defer conn.Close()			for {				buf := make([]byte, 65535)				// リモートサーバ(target)の返信を受信する				n, src, err := conn.ReadFrom(buf)				if err != nil {					panic(err)				}				// レスポンスデータをクライアントに返信して				_, err = pc.WriteTo(packetResponse(src, buf[:n]), addr)				if err != nil {					panic(err)				}			}		}() 		// 初めてマッピングサーバをNATテーブルに保存して		natTable[addr.String()] = conn	} 	target, remain := getTargetAddress(buf[:n]) 	// リモートサーバにデータを送信して	_, err = conn.WriteTo(remain, target)	if err != nil {		panic(err)	}}

0 件のコメント

©2026Asutorufa