トンネルとは、ある通信を別の通信でカプセル化することを指します。選定にあたっては、「いったい何を転送したいのか」という問いに答えなければなりません。改造できないデバイスのEthernetフレーム、サブネット全体のIPパケット、それとも特定サービスのTCP接続か。これらのニーズは、ブロードキャスト範囲、ルーティング動作、権限の境界が異なり、単に製品のパフォーマンスだけで順位付けすることはできません。
転送対象をまず決定し、その後でカプセル化と保護方法を選択する
レイヤ2フレーム
MACアドレス、ブロードキャストドメインなどのセマンティクスが必要
VXLAN / Geneve
レイヤ3パケット
アドレスまたはサブネットの接続
IPIP / GRE / WireGuard
サービス接続
指定されたTCP/UDPサービスのみを開放
rathole / frp
トンネルの階層と暗号化は異なる次元です。VXLANは暗号化を積み重ねることができ、ポートフォワーディングもエンドツーエンドTLSを担うことができます。
ニーズ 最初に考慮すべき機能 追加されがちな責任
信頼できるネットワーク間でIPパケットを転送する IPIP、GREなどのカプセル化 到達性、フィルタリング、MTU。必要に応じて別途暗号化を追加
信頼できないネットワーク経由でサブネットを接続する WireGuard、IPsecなどの安全なトンネル 鍵、アイデンティティ、ルーティングと戻り経路
デバイスのアイデンティティと変動するネットワークを自動管理する Tailscaleのようなオーバーレイプラットフォーム コントロールプレーン、ポリシー伝播、リレー依存
レイヤ3ネットワーク内でレイヤ2ネットワークを構築する VXLAN、Geneve MAC/ネイバー学習、BUMトラフィック、コントロールプレーン
外部から少数の内部サービスにアクセスする リバースプロキシまたはポートフォワーディング パブリックエントリの権限、プロキシの信頼性、サービスの復旧
「デプロイ可能」かどうかを判断するには、既存のデバイスが対応しているか、運用側が鍵とルーティングを管理できるか、出口で必要な転送が許可されているかも考慮する必要があります。デバイスがIPsecのオフロードに対応しているからといって、特定のアルゴリズム、カプセル化、トラフィックがオフロードパスを通過するとは限りません。
IPIPとGRE:最も単純なIPカプセル化は同じプロトコルではない
IPv4-in-IPv4は、元のIPv4パケットの直前に新しいIPv4ヘッダを追加し、外側のProtocolフィールドは4となります。オプションがない場合、20バイトが追加されます。GREはプロトコル番号47を使用し、さらに4バイトの基本GREヘッダを持ち、その中のProtocol Typeフィールドがカプセル化されたプロトコルを示します。したがってGREはより汎用的ですが、「ヘッダのないIPIP」と呼べるものではありません。IP-in-IP RFC 2003 、GRE RFC 2784
GREは拡張フィールドとしてKey、シーケンス番号、チェックサムなどを携带できます。長さは固定の4バイトである必要はありません。Keyは論理トンネルを区別するために使用できますが、認証資格としては機能しません。攻撃者は暗号化の秘密鍵を知らなくても、同じKeyを構築することができます。基本のIPIPとGREは、どちらもペイロードの機密性を提供しません。
内側が1400バイトのIPv4パケットであると仮定します。オプションなしのIPv4-in-IPv4は1420バイト、基本GRE over IPv4は1424バイトとなります。ここでは外側のEthernetヘッダは含まれておらず、暗号化も追加されていません。この数字を「オンラインでのバイト占有量」と比較する際は、同じ階層の口径で揃える必要があります。
VXLANとGeneve:トンネル自体が完全な仮想ネットワークコントロールプレーンではない
VXLANは内側のEthernetフレームをUDPにカプセル化します。基本VXLANヘッダは8バイトで、VNI(VXLAN Network Identifier)は24ビットです。VNIは論理ネットワークを示すものであり、暗号化キーではありません。同じVNIへの誤ったアクセスを防ぐには、下層の分離とエントリポイントでの検証が必要です。UDPのソースポートは、外側のECMPにおけるトラフィックのハッシュ分散に使用できますが、すべてのパケットでランダムにパスを変更する必要があるわけではありません。VXLAN RFC 7348
Geneveの基本ヘッダも8バイトですが、可変長のオプションをサポートしており、ネットワーク仮想化のメタデータ携带に適しています。計算オーバーヘッドを評価する際は、実際のオプション長を加算する必要があります。理解できない重要なオプションに出会った場合、処理ルールがパケットの受信可否に影響を与えるため、オプションをすべてのエンドポイントに対して透過的な装飾として扱うことはできません。Geneve RFC 8926
カプセル化はパケットの搬送方法を示すだけで、遠端のMACアドレスがどこにあるか、不明なユニキャストを誰に送信すべきか、ブロードキャストをどのように複製するかは説明しません。学習、静的設定、またはEVPNなどのコントロールプレーンがこれらの問題を担います。レイヤ2の拡張は、ブロードキャストと障害の影響をより多くの場所に持ち込みます。アプリケーションがユニキャストIPの相互通信のみを必要とする場合、本当に同じブロードキャストドメインを必要としているかどうかをまず判断すべきです。
なぜVXLANでMTUが必ず9000である必要はないのか
VLANなし、内側フレームがFCSを持たず、外側IPv4にオプションがない場合を例とします。1500バイトの内側IPパケットに、内側Ethernet 14バイト、VXLAN 8バイト、UDP 8バイト、外側IP 20バイトを加えると、合計1550バイトの外側IPパケット となります。重要なのはパスがこのサイズをサポートしていることであり、9000は単なるネットワーク設定の一つに過ぎません。内側MTUを下げることでも対応可能であり、任意のフラグメンテーションを無代价な救済策として扱うことはできません。
inner_ip = 1500
encapsulation = {
' IPIP/IPv4' : 20 ,
' GRE-basic/IPv4' : 20 + 4 ,
' VXLAN/IPv4' : 20 + 8 + 8 + 14 ,
' VXLAN/IPv6' : 40 + 8 + 8 + 14 ,
' Geneve/IPv4+16B-options' : 20 + 8 + 8 + 16 + 14 ,
}
assert inner_ip + encapsulation [ ' VXLAN/IPv4' ] == 1550
assert 1500 - encapsulation [ ' VXLAN/IPv4' ] == 1450
assert 1500 - encapsulation [ ' VXLAN/IPv6' ] == 1430
assert 1500 - encapsulation [ ' Geneve/IPv4+16B-options' ] == 1434
assert 1550 + 14 + 4 == 1568
print ( ' 外側IP長を基準としたカプセル化予算の計算が通過した' )
内側のVLAN、追加の暗号化、または第2のレイヤトンネルも、引き続き予算を消費します。TCP MSSはTCPデータセグメントに影響を与えるのみです。MSSを下げるだけでは大規模なUDPデータグラムは解決できず、すべてのパスでのPMTU処理を代替できるわけではありません。
1500バイトの内側パケット、外側には本当に収まるのか?
まずVXLANのIPv4とIPv6の外側を比較すると、内側の上限は20バイト異なります。次にESPを選択し、内側長を1438から1439に増やした場合、外側は1バイトだけ増えるのではなく、アライメントのために1500から1504へと段差をつけて増加します。予算にはこのような離散的な変化を含める必要があります。
図を準備しています 再読み込み
1500バイトの内側パケット、外側には本当に収まるのか? 各レイヤのヘッダは、共通の予算から逐次差し引く必要があります。VXLANには内側Ethernetヘッダも含まれます。ESPのアライメントにより、総長は階段状に増加します。
{"id":"tunnel-layer-budget","title":"1500バイトの内側パケット、外側には本当に収まるのか?","summary":"各レイヤのヘッダは、共通の予算から逐次差し引く必要があります。VXLANには内側Ethernetヘッダも含まれます。ESPのアライメントにより、総長は階段状に増加します。","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><div class=\"presets\" role=\"group\" data-i18n-label=\"mode\"><button data-mode=\"gre\" data-i18n=\"gre\"></button><button data-mode=\"vx\" data-i18n=\"vx\"></button><button data-mode=\"esp\" data-i18n=\"esp\"></button></div><label class=\"form-field\"><span data-i18n=\"ip\"></span><select id=\"ip\"><option value=\"20\">IPv4 (20 B)</option><option value=\"40\">IPv6 (40 B)</option></select></label><div class=\"control\"><label for=\"inner\" data-i18n=\"inner\"></label><output for=\"inner\" id=\"inner-value\"></output><input id=\"inner\" type=\"range\" min=\"40\" max=\"1600\" value=\"1500\" step=\"1\"></div><div class=\"control\"><label for=\"mtu\" data-i18n=\"mtu\"></label><output for=\"mtu\" id=\"mtu-value\"></output><input id=\"mtu\" type=\"range\" min=\"1280\" max=\"1600\" value=\"1500\" step=\"1\"></div><div id=\"packet\" class=\"budget\"></div><div class=\"metrics\"><div><span data-i18n=\"total\"></span><strong id=\"total\"></strong></div><div><span data-i18n=\"ceiling\"></span><strong id=\"ceiling\"></strong></div></div><p id=\"equation\" class=\"formula\"></p><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:500;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:500 20px var(--viz-font-ui)}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:var(--viz-font-mono);font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px var(--viz-font-ui);background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n/* Action labels must remain readable across locales and narrow embeds. */\n.actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}\n.actions button{overflow-wrap:anywhere;white-space:normal;min-height:58px;padding:8px}\nbutton{overflow-wrap:anywhere}\n@media(min-width:640px){.actions{grid-template-columns:repeat(3,minmax(0,1fr))}}\n\n.metrics span{overflow-wrap:anywhere}\n.panel{border:1px solid var(--rule);border-radius:9px;padding:12px;margin:14px 0;min-width:0}.panel h3{font-size:13px;margin:0 0 10px;color:var(--muted)}.source{font:13px/1.8 var(--viz-font-mono);white-space:pre-wrap;overflow-wrap:anywhere;margin:12px 0}.source mark{background:var(--accent-soft);color:var(--ink);border-bottom:2px solid var(--accent)}.source .fault{background:var(--second-soft);border-color:var(--second)}.diagram{display:block;width:100%;height:auto;max-height:320px;margin:14px 0;overflow:visible}.diagram text{fill:var(--ink);font:12px var(--viz-font-ui)}.diagram .edge{stroke:var(--muted);stroke-width:1.5;fill:none}.diagram .edge.on{stroke:var(--accent);stroke-width:3}.diagram .node{fill:var(--surface);stroke:var(--rule);stroke-width:1.5}.diagram .node.on{fill:var(--accent-soft);stroke:var(--accent)}.diagram .node.gold{fill:var(--second-soft);stroke:var(--second)}.log{font:12px/1.8 var(--viz-font-mono);white-space:pre-line;overflow-wrap:anywhere;min-height:7.2em}.table{display:grid;gap:5px;margin:14px 0}.table .tr{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px}.table .tr>*{padding:8px 5px;background:var(--surface);border-radius:4px;min-width:0;overflow-wrap:anywhere;font-size:12px}.table .tr .on{background:var(--accent-soft)}.table .tr .gold{background:var(--second-soft)}.choices button{min-height:44px}.metrics strong{min-height:1.6em}.code-line{display:block}.code-line.on{background:var(--accent-soft);border-left:2px solid var(--accent);padding-left:6px}.status-badge{font-size:12px;color:var(--accent)}.tile-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.tile-grid .cell{min-height:40px}.actions button{min-height:48px}.form-field{display:grid;gap:8px;margin:14px 0;font-size:13px}.form-field input{width:100%;font-family:var(--viz-font-ui)}.metrics.three{grid-template-columns:repeat(3,minmax(0,1fr))}.formula{min-height:3.2em}.presets{flex-wrap:wrap}.presets button{flex-basis:25%;min-height:44px}\n\n.budget{display:flex;height:28px;margin:16px 0;background:var(--surface);border-radius:5px;overflow:hidden}.budget i{display:block;background:var(--accent);transition:width .2s}.budget i.gold{background:var(--second)}.intervals{margin:16px 0}.interval{position:relative;height:36px;background:var(--surface);margin:6px 0;border-radius:4px;overflow:hidden}.interval i{position:absolute;height:100%;background:var(--accent-soft);border-left:2px solid var(--accent)}.interval i.gold{background:var(--second-soft);border-color:var(--second)}.interval span{position:relative;z-index:1;font:12px/36px var(--viz-font-ui);padding-left:7px}.table .tr>*{min-height:4.8em}.formula{white-space:pre-line;min-height:7.2em}.actions:has(>button:only-child){grid-template-columns:1fr}.metrics strong{min-height:3.2em}.rangegrid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:3px;margin:14px 0}.rangegrid .cell{min-height:30px;padding:3px 1px;font-size:10px}.message{min-height:7.2em;white-space:pre-line;font:13px/1.8 var(--viz-font-ui);overflow-wrap:anywhere}\n/* Allow CJK hanging punctuation without overflowing a metric's border box. */\n.metrics>div{padding-right:4px}.metrics span{line-break:anywhere}\n\n","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}const esc=s=>String(s).replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));const fmt=s=>'{'+[...s].sort().join(', ')+'}';function graph(id,nodes,edges){const el=$('#'+id);el.setAttribute('viewBox','0 0 360 200');el.innerHTML='<defs><marker id=\"arrow-'+id+'\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--muted)\"/></marker></defs>'+edges.map(e=>{const a=nodes[e[0]],b=nodes[e[1]],dx=b.x-a.x,dy=b.y-a.y,d=Math.hypot(dx,dy)||1;if(edges.some(r=>r[0]===e[1]&&r[1]===e[0])){const nx=-dy/d,ny=dx/d;return '<path class=\"edge '+(e[2]?'on':'')+'\" d=\"M '+(a.x+dx/d*22+nx*12)+' '+(a.y+dy/d*22+ny*12)+' Q '+((a.x+b.x)/2+nx*38)+' '+((a.y+b.y)/2+ny*38)+' '+(b.x-dx/d*25+nx*12)+' '+(b.y-dy/d*25+ny*12)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}return '<line class=\"edge '+(e[2]?'on':'')+'\" x1=\"'+(a.x+dx/d*25)+'\" y1=\"'+(a.y+dy/d*25)+'\" x2=\"'+(b.x-dx/d*28)+'\" y2=\"'+(b.y-dy/d*28)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}).join('')+nodes.map(n=>'<g><circle class=\"node '+(n.cls||'')+'\" cx=\"'+n.x+'\" cy=\"'+n.y+'\" r=\"25\"/><text x=\"'+n.x+'\" y=\"'+(n.y+4)+'\" text-anchor=\"middle\">'+esc(n.name)+'</text>'+(n.sub?'<text x=\"'+n.x+'\" y=\"'+(n.y+43)+'\" text-anchor=\"middle\">'+esc(n.sub)+'</text>':'')+'</g>').join('');}function table(id,rows){$('#'+id).classList.add('table');$('#'+id).replaceChildren(...rows.map(r=>{const row=document.createElement('div');row.className='tr';r.forEach(x=>{const c=document.createElement('div');if(typeof x==='object'){c.textContent=x.text;c.className=x.cls||'';}else c.textContent=x;row.append(c)});return row;}));}function band(id,parts,total){$('#'+id).replaceChildren(...parts.map((p,i)=>{const e=document.createElement('i');e.style.width=(100*p.value/total)+'%';e.className=i%2?'gold':'on';e.title=p.name+': '+p.value;return e}));}function intervals(id,items,total){$('#'+id).replaceChildren(...items.map(p=>{const row=document.createElement('div');row.className='interval';const bar=document.createElement('i');bar.style.left=(100*p.start/total)+'%';bar.style.width=(100*(p.end-p.start)/total)+'%';bar.className=p.cls||'';const label=document.createElement('span');label.textContent=p.label;row.append(bar,label);return row;}));}let mode='vx';function size(n){const ip=+$('#ip').value;return mode==='gre'?n+ip+4:mode==='vx'?n+ip+30:n+ip+8+8+8+2+16+((4-(n+2)%4)%4)}function draw(){const n=+$('#inner').value,mtu=+$('#mtu').value,total=size(n);let ceiling=0;for(let i=0;i<=mtu;i++)if(size(i)<=mtu)ceiling=i;set('inner-value',n);set('mtu-value',mtu);band('packet',[{name:'inner IP',value:n},{name:'encapsulation',value:total-n}],Math.max(total,mtu));set('total',total+(total<=mtu?' ✓':' ✗'));set('ceiling',ceiling);set('equation','inner '+n+' + overhead '+(total-n)+' = '+total+'\\n'+total+' ≤ MTU '+mtu+' : '+String(total<=mtu));$('#total').dataset.value=total;$('#ceiling').dataset.value=ceiling;pressed(mode);}document.querySelectorAll('input,select').forEach(e=>e.oninput=draw);document.querySelectorAll('[data-mode]').forEach(b=>b.onclick=()=>{mode=b.dataset.mode;draw()});draw();","audio":false,"strings":{"ceiling":"収められる最大内側IP(B)","esp":"ESP-GCM NAT-T","gre":"GRE","heading":"1500バイトの内側パケット、外側には本当に収まるのか?","inner":"内側IP総長(B)","intro":"カプセル化、外側IPバージョン、パスMTUを選択し、図ではすべて外側IPの総長を基準としています。","ip":"外側IPバージョン","mode":"カプセル化","mtu":"パスMTU(B)","reset":"リセット","scope":"VLAN/FCS/IPオプションなし;GRE基本4バイト;VXLAN 8+UDP 8+内側Ethernet 14;ESP AES-GCM/UDPは8バイトIV、16バイトタグ、4バイトアライメントを含む。単一パケットの予算で計算し、フラグメンテーションはシミュレートしない。","scopeLabel":"モデルの範囲と前提条件","total":"外側IP総長(B)","vx":"VXLAN"}}
WireGuard、IPsec、プラットフォーム機能は別々に比較すべき
WireGuard は、ピアの公開鍵、AllowedIPs、UDPデータプレーンを組み合わせていますが、プロトコル自体には完全なユーザーディレクトリや一般的な自動NAT透過サービスは含まれていません。IPsec/IKEv2 はポリシーとSA(セキュリティ・アソシエーション)によってIPトラフィックを保護し、認証、アルゴリズムのネゴシエーション、デバイス間の相互運用においてより豊富な設定空間を持ちます。パフォーマンスは実装、アルゴリズムのアクセラレーション、パケット長、コア数、リンクによって決定され、環境を問わず常に優位な「チャンピオン」は存在しません。
Tailscale はWireGuardの上にアイデンティティ、ポリシー配布、発見、リレー機能を追加します。それは単なる裸のWireGuardとの違いではなく、デプロイコストを比較する際には、ピア、公開鍵、ルーティングを手動で保守する作業量と、プラットフォームコントロールプレーンへの依存度を計算に入れる必要があります。
「エンドツーエンド暗号化」のエンドポイントを明確にする必要があります。2台の業務ホストがそれぞれトンネルを終端する場合と、2台のゲートウェイ間のトンネルでは異なります。後者の場合、ゲートウェイを出た後は平文ネットワークを通過し続ける可能性があります。アプリケーションTLSを使用することで、さらに遠くのエンドまで保護を提供できます。
リバーストンネル:内部ネットワークのクライアントが能動的に外向き接続を行い、パブリックエンドでアクセスを受信する
通常の公開ネットワークポートフォワーディング方式では、内部ネットワークのプロキシCが公開ネットワークのプロキシSに能動的に接続し、Sが外部接続をCに転送し、Cがローカルサービスに接続します。これにより、内部ネットワークへの直接のインバウンドアクセスという要件を回避できますが、公開ネットワークのSは依然として到達可能である必要があり、Cのアウトバウンド接続も許可されている必要があります。ここでは、訪問者から内部ネットワークへのUDPホールパンチングの確立は必須ではありません。
リバース接続はエントリの到達性を解決し、アプリケーションの暗号化がコンテンツを閲覧できる誰かを決定する
訪問者
パブリックエントリに接続
パブリックプロキシ S
サービスポートをリスニング
内部プロキシ C
ローカルサービスに接続
C が S へのアウトバウンドトンネルを能動的に確立
転送
TLS透通:アプリケーションTLSはS、Cを跨ぎ、オリジンサーバーで終端される
S でTLS終端:S はアプリケーションの平文を読み取ることができ、S—C間は別途保護が必要
トンネル登録トークンはプロキシクライアントの認証を行う;公開サービスには独自のアクセス認証と認可が必要。
ratholeとfrpの一般的なデプロイメントにはどちらもserver/clientの役割がありますが、前者が天然に非対称で分散型であり、後者が集中構造であると記述することはできません。ratholeの現在のリポジトリ設定はTCPとUDPサービスをサポートし、TLS、Noiseなどの転送オプションを提供しており、「TCPのみをサポートし、暗号化はCaddyに依存する」という記述は正確ではありません。rathole プロジェクト 、転送設定
比較項目 rathole frp
一般的なデプロイメント パブリックサーバーと内部クライアント frps と frpc
サービス能力 サービスごとにTCP/UDP転送を設定 TCP/UDP、HTTP/HTTPSなど多様なプロキシ
転送保護 TLSまたはNoiseを設定可能 TLSなどの転送設定をサポート
コネクションリユース/プール 使用しているバージョンと実装による ドキュメントでTCPリユースとコネクションプールのサポートを明確に明記
リソース評価 自社の同時実行数、パケット長、バッファで測定 同一負荷とバージョンの口径で測定
製品がUDPサービスをサポートしていることと、「プロキシ間で必ずネイティブUDP転送が行われる」ことは別問題です。UDPデータが信頼性のあるストリームで転送される場合、パケットロスとキューヘッドブロッキングの動作が変化します。複数の業務接続が1つのTCP転送を共有する場合、外側のパケットロス回復が他のリユース接続に影響を与える可能性があります。frp ネットワーク設定
コネクションプールがすべてのハンドシェイクを解消できない理由
プールは、一部のコネクション準備作業をビジネスリクエストの到着前に移動させ、ヒット時に待ち時間を削減します。リユースは、複数の論理コネクションが既存の転送を共有することを許可します。frpはこれらのメカニズムの両方をサポートしているため、「ratholeは事前に構築し、frpは常にリクエストごとに新規TCPを確立する」という記述を両者の根本的な違いとして使うことはできません。
S—Cチャネルが準備されていても、訪問者からSへの接続、Cからローカルサービスへの接続、およびアプリケーションTLS/ログイン手順が存在する可能性があります。プール内コネクションが無効になった場合は、検出と補充が必要です。early eof を唯一の原因をNATのアイドルタイムアウトに帰属させることはできず、相手側のクローズ、プロセス終了、またはプロトコルの不一致によっても発生し得ます。
例えば、リクエストがオンデマンドでチャネルを確立する際に追加で40msの待ち時間が発生し、事前準備チャネルのヒット率が90%であると仮定します。この項目のみを計算すると、平均待ち時間は4msとなります。残りの10%のリクエストには依然として40msの待ち時間が存在し、平均値だけでテールレイテンシが消失したとは言えません。プールが大きくなると、より多くのFD、メモリ、ゲートウェイの状態を占有します。
エントリポイントTLSとトンネル暗号化:2つの異なる終端位置
CaddyがSでブラウザのTLSを終端する場合、SはHTTPの平文を見ることができます。S—C間のTLS/Noiseを有効にすることで転送を継続して保護できますが、Sを業務コンテンツを見えない中継ポイントに戻すわけではありません。訪問者からオリジンサーバーまでアプリケーションTLSを透通させる場合、Sは対応する暗号文を転送するだけであり、証明書とアプリケーションの認証はオリジンサーバーが担当します。
プロキシ登録トークンは、Cが特定の転送サービスに登録する権限を持っていることを証明するものであり、パブリックリスニングポートにアクセスするすべてのユーザーを自動的に検証するものではありません。公開管理ページ、データベースポート、またはファイルサービスの場合、アクセス制御は実際のエントリポイントまたはアプリケーションで実施する必要があります。トンネルの両側にトークンを1つ設定するだけでは、そのサービスがプライベート化されたことを意味しません。
完全なシナリオを使って選択を行う
3人の同僚が家庭用NASの管理ページにアクセスする必要があると仮定します。訪問者はクライアントをインストールでき、公開アクセスは不要です。まず、デバイスオーバーレイネットワークソリューションのメンバー承認、クライアントサポート、復旧コストを比較します。管理ページをパブリックネットワークに公開し、追加のエントリ認証を重ねる必要はありません。
目標がクライアントインストール不要の公開デモサイトに変更された場合、リバースHTTPプロキシがエントリ形式として適切であり、次にTLS終端、ドメイン名、オリジンサーバーのアイデンティティ、リクエストサイズ/タイムアウトを決定します。目標が多数のIPサービスを持つ2つのサブネットを接続することに変更された場合、ゲートウェイVPN、ルーティング、戻り経路を比較します。アプリケーションがレイヤ2の発見や特定のEthernetセマンティクスを必要とする場合にのみ、レイヤ2オーバーレイネットワークとブロードキャスト境界の評価を続行します。
これらの判断は、製品の永久的なランキングではありません。評価レポートには少なくとも、データが実際に誰を通り、誰が復号でき、何へのアクセスが許可され、最大有効パケット長はどれくらいか、満負荷時のメモリ使用量とテールレイテンシ、そしてコントロール接続の切断後に新旧の業務がそれぞれどうなるかを示す必要があります。「軽量、低レイテンシ、エンタープライズ級」とだけ書いても、それに基づいて再現したりトレードオフを決定したりすることはできません。