PACファイルを記述する必要がない10の例

画像







はじめに



ZscalerなどのクラウドベースのSaaSソリューションであろうと、Cisco WSA(IronPort)などのオンプレミスアプライアンスであろうと、Web Security Gatewayのほとんどすべての実装は、特定の場合にブラウザーでプロキシサーバーを構成せずにはできません。プロキシサーバーの自動構成ファイル(PAC、プロキシの自動構成)。 この記事では、パフォーマンスを最適化するいくつかの例を検討します。







なぜこの記事が必要なのですか?



この記事を書くことにしたのはなぜですか? そう願っています、それが理由です。 実際、PACファイルは、リソースのプロキシサーバー名を返すか、プロキシをバイパスしてリソースへの直接アクセスを使用するようにブラウザーに指示する、文字列/サブストリングがURL /ホストフィールドに一致する文字列を検索するJavaScript関数です。 他のプログラミング言語と同様に、JavaScriptコードも実行用に最適化できます。 複雑な分散型インターネットアクセスインフラストラクチャを備えた大企業/企業、およびその結果、数百行のコードで構成されるPACファイルのコンテキストでは、PACファイルを最適化するタスクはもはや完全に役に立たないようです。 、最適ではない、または場違いで使用されていない1つの関数の実行時間の割合は、明らかに、コード内でのその関数の発生(アプリケーション)の数で乗算されます。







さらにカットの下。









免責事項



この記事では、PACファイルで使用される機能を詳細に説明するつもりはありません。 各機能の詳細については、 http://findproxyforurl.comなどのサイトに問い合わせることをお勧めします。 この記事のさまざまなブラウザーのパフォーマンステストの結果は議論の余地があり、絶対的な真実であると主張することはできませんが、著者は真の結果を達成するためにあらゆる努力を試みました。 それにもかかわらず、示された論争の理由で、要約テスト結果は提示されません-読者は、特定のアプローチを使用する利点を独立して検証するように招待されます。 これを行うために、可能であれば、テストへのリンクが提供されます。 私の研究では、主にリソースjsperf.comに依存していました。これは、githubでテストスクリプトを作成し、JavaScriptコードのパフォーマンスを測定するアカウントがある場合に非常に便利です。ここに、この記事のテストスクリプトが格納されます。







さて、ビジネスに取り掛かりましょう。







最初の例



リストの最初は、厳密に定義されたホストのプロキシを選択する必要がある最も単純なケースです。 非常に多くの場合、同僚は何らかの理由でURLチェックアウトを使用するか、文字列「*」をフレーム化します。 多くの場合、これはPACファイルの長さがすでに100行を超えており、誰かが次のような類推によって新しい条件を追加した場合に発生します。







else if (shExpMatch(url,"*cisco.com*")) return 'PROXY MyProxy1:3128';
      
      





またはホストで:







 else if (shExpMatch(host,"cisco.com")) return 'PROXY MyProxy1:3128';
      
      





ここでの問題は、Chrome 58とIE11の最初のオプションがほぼ1%遅い(Firefox 53ではほとんど違いがない)ことでさえないことです。ここで最も悪いのは、多くの読者がURLについて推測していることです。たとえば、「 http://www.noncisco.com/evil/cisco.com 」の場合、 両方の結果がtrueを返します。 この問題の解決策は非常に簡単です。shExpMatch関数は使用しないでください。これは意図されていませんが、完全に一致するものを探します。







  if (host == 'www.cisco.com') return 'PROXY MyProxy1:3128';
      
      





欠点も明らかです。 上記のコードはhttp://cisco.comに対してfalseを返しますが、もちろん次の2つのチェックを行うことを妨げるものはいません。







  if ((host == 'www.cisco.com') || (host == 'cisco.com')) return 'PROXY MyProxy1:3128';
      
      





実際には、パフォーマンスを検証したい人のためのテストへのリンク: https : //jsperf.com/inefficient-shexpmatch







ところで、PACファイルをテストする方法は? 実際にブラウザでそれらを手動で反復しないでください? この方法は最後通告になりますが、私はまだこれらの目的のためにhttp://home.thorsen.pm/proxyforurlリソースを使用していますが、これはまだ私を失望させたりorしたりしていません。







2番目の例



問題番号2は本質的に上記で検討したものに非常に近いものであり、ここでも彼らは私が好きではない関数を使用しています デフォルトで shExpMatch。

タスクは、特定のドメインにMyProxy2を使用することです。 何をする:







 if (shExpMatch(host, "*.linkedin.com")) return 'PROXY MyProxy2:3128';
      
      





繰り返しますが、最適ではなく、正確ではありません。 関数を使用します







 if (dnsDomainIs(host,".linkedin.com")) return 'PROXY MyProxy2:3128';
      
      





厳密に言えば、FFブラウザーとChromeブラウザーではこれらの機能のパフォーマンスはほぼ同等ですが、IE11ではこれは重要であり、その差は1%以上です。

実際には、テスト:

https://jsperf.com/dnsdomainis-vs-shexpmatch







例3



問題3は、管理者の不注意が原因で頻繁に発生し、重複した状態にあります。 例:







 else if (shExpMatch(host, "192.168.*")) return "DIRECT"; else if (shExpMatch(host, "10.*.*.*")) return "DIRECT"; … else if (isInNet(host, "192.168.88.0", "255.255.255.0")) return "DIRECT"; … else if (shExpMatch(url, "*10.10.*")) return "DIRECT";
      
      





条件が相互に重複(重複)するだけでなく、ユーザーがブラウザのアドレスバーにipv4アドレスではなくドメイン名を入力した場合、原則として機能しません。 解決策は、少なくとも次のように、重複する条件を除外して名前解決を実行することです。







 else if (shExpMatch(dnsResolve(host), "192.168.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "10.*.*.*")) return "DIRECT";
      
      





例4



実際、問題番号4は、前のセクションで説明した内容の開発です。 管理者が、クライアントにRFC1918範囲のすべてのサブネットのプロキシをバイパスするよう指示し、これを行うとします。







 else if (shExpMatch(dnsResolve(host), "192.168.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "10.*.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.16.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.17.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.18.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.19.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.20.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.21.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.22.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.23.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.24.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.25.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.26.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.27.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.28.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.29.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.30.*.*")) return "DIRECT"; else if (shExpMatch(dnsResolve(host), "172.31.*.*")) return "DIRECT"; …
      
      





もちろん、名前解決を一度実行してから、結果が書き込まれる変数を既に使用するようにお願いします。







 var resolved_ip = dnsResolve(host); ... else if (shExpMatch(resolved_ip, "192.168.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "10.*.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.16.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.17.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.18.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.19.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.20.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.21.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.22.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.23.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.24.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.25.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.26.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.27.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.28.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.29.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.30.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.31.*.*")) return "DIRECT"; ...
      
      





18の最悪の名前解決要求(最後の場合)の代わりに、予測可能なパフォーマンスと名前解決を1回だけ取得します。これは、テストを追加しなくても間違いなく効率的です。







5番目の例



最適化再帰を継続します。 前の問題のコードブロックは、そのサイズのため、最適化を示唆しています。 最初に、関数が次のようになったとします。







 function FindProxyForURL(url, host) { var resolved_ip = dnsResolve(host); if (shExpMatch(resolved_ip, "127.*.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "192.168.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "0.*.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "10.*.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.16.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.17.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.18.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.19.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.20.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.21.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.22.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.23.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.24.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.25.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.26.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.27.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.28.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.29.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.30.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "172.21.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "169.254.*.*")) return "DIRECT"; else if (shExpMatch(resolved_ip, "192.88.99.*")) return "DIRECT"; ... }
      
      





上記のコードを最適化し、他の場合ではなく論理or(||)を使用した場合でも、前述の3つのブラウザーのテスト結果によると、次のように正規表現チェックを使用することが最適であることがわかりました。







 function FindProxyForURL(url, host) { var privateIP = /^(0|10|127|192\.168|172\.1[6789]|172\.2[0-9]|172\.3[01]|169\.254|192\.88\.99)\.[0-9.]+$/; var resolved_ip = dnsResolve(host); if (privateIP.test(resolved_ip)) { return "DIRECT"; } }
      
      





これはより効率的であるだけでなく、よりコンパクトでエレガントに見えることに注意してください。 ただし、完璧に制限はありません。特殊なIsInNet関数を使用すると、さらに素晴らしい結果を得ることができます。 前の例と比較すると、以下のコードは、さまざまなブラウザーで0.2〜2%のパフォーマンスの向上をもたらします。







 function FindProxyForURL(url, host) { var resolved_ip = dnsResolve(host); if ((isInNet(resolved_ip , "192.168.0.0", "255.255.0.0")) || (isInNet(resolved_ip , "172.16.0.0", "255.240.0.0")) || (isInNet(resolved_ip , "10.0.0.0", "255.0.0.0")) || (isInNet(resolved_ip , "127.0.0.0", "255.0.0.0")) || (isInNet(resolved_ip , "0.0.0.0", "255.0.0.0")) || (isInNet(resolved_ip , "169.254.0.0", "255.255.0.0")) || (isInNet(resolved_ip , "192.88.99.0", "255.255.255.0"))) return "DIRECT"; }
      
      





ここで、テスト自体を繰り返すことができます: https : //jsperf.com/privateip-test-vs-shexpmatch







例6



変更のためのメインラインからのわずかな逸脱。 以下の2行のコードを検討してください。







 dnsDomainIs("www.notmycompany.com", "mycompany.com") dnsDomainIs("www.MyCompany.com", "mycompany.com")
      
      





最初の行が期待されるtrueを返した場合(はい、はい、true、それは部分文字列を検索するだけです!)、2番目の行は、一見完全に一致しているにもかかわらず、大文字の違いによりfalseを返します(ところで、FFのようにバージョン52の場合、結果は依然として真実ですが、著者はネットワークの広大な範囲のどこかでそれを読み、個人的にそれを確認しませんでした)。







したがって、この問題を解決するには、PACファイルの先頭でURLとホスト文字列の変換を実行することが非常に望ましいです。たとえば、次のようにさらに操作する場合







 var url_lc = url.toLowerCase(); var host_lc = host.toLowerCase();
      
      





さらに、url_lcおよびhost_lcでのみ動作します。







例7



非常に単純な問題ですが、それほど一般的ではありません。 多くの問題と同様に、これは不注意から生じます。以下の例は実際の実装の例から取られていますが、名前はもちろん架空のものであり、偶然の一致は純粋な偶然です。







 ... else if (shExpMatch(host, "files.company.ru")) return "PROXY companyproxy7:3128"; else if (shExpMatch(host, "mail.company.ru")) return "PROXY companyproxy7:3128"; else if (shExpMatch(host, "company.com")) return "PROXY companyproxy7:3128"; else if (shExpMatch(url, "*downloads*.company.com*")) return "PROXY companyproxy7:3128"; else if (shExpMatch(host, "global.company.com")) return "PROXY companyproxy7:3128"; else if (shExpMatch(host, "db.company.com")) return "PROXY companyproxy7:3128"; else if (shExpMatch(host, "test.company.com")) return "PROXY companyproxy7:3128"; else if (shExpMatch(host, "blog.company.com")) return "PROXY companyproxy7:3128"; else if (shExpMatch(host, "servicedesk.company.com")) return "PROXY companyproxy7:3128"; else if (shExpMatch(url, "*training.company.com*")) return "PROXY companyproxy7:3128"; else if (shExpMatch(url, "*farm.company.com*")) return "PROXY companyproxy7:3128"; else if (shExpMatch(host, "*.fa.company.com")) return "PROXY companyproxy7:3128"; else if (shExpMatch(url, "https://servicedesk.company.com/*")) return "PROXY companyproxy7:3128"; else if (shExpMatch(url, "https://servicedesk.company.com:8080/*")) return "PROXY companyproxy7:3128"; …
      
      





そして、ファイルの最後に次のようなものが表示されます(さらにコメント付きです!):







 /* Default Traffic Forwarding */ return "PROXY companyproxy7:3128";
      
      





前に既に検討した問題に加えて、上記のコードブロックはまったく役に立たず、ブラウザーの速度を低下させるだけです。最終的には、デフォルトで同じプロキシサーバーが使用されるためです。







8番目の例



問題番号8は、会社の内部リソースに関連しています。

このコードがあるとしましょう:







 if (host == 'internal') return 'DIRECT'; if (host == 'mail') return 'DIRECT'; if (host == 'files') return 'DIRECT';
      
      





つまり、PACファイルは、検索ドメインがPCに設定されているため、ドメインを指定せずにブラウザがホスト名で内部リソースにアクセスしたかどうかを確認します。 このようなチェックを最適化するための優れたソリューションは、1つの関数のみを使用することです。







  if (isPlainHostName(host)) { return 'DIRECT';
      
      





例9



最適化タスク番号9は以前のものに近く、組織の内部リソースを使用すると再び表示されます。 以下の例のように、ユーザーがドメインの有無にかかわらず同じサイトをリクエストできる場合はどうなりますか?







 if (host == 'mail') return 'DIRECT'; if (host == 'mail.resource.lan') return 'DIRECT'; if (host == 'files') return 'DIRECT'; if (host == 'files.resource.lan') return 'DIRECT';
      
      





localHostOrDomainIs関数を使用する場合、このようなチェックの最適化は非常に簡単です。







 if (localHostOrDomainIs(host, "mail.resource.lan") return 'DIRECT'; if (localHostOrDomainIs(host, "files.resource.lan”) return 'DIRECT';
      
      





例10



if条件の最適化に関する議論のある問題。 一番下の行は、PACファイルでifの条件をチェックした後、ほとんどの場合、FindProxyForURL関数から戻りがありますが、なぜ以下の構成を使用するのですか?







 if .. else if .. else
      
      





FFテストの結果は、OR条件(||)の使用が最適であることを示唆しています。







画像







Chromeの場合、結果はわずかに異なりますが、if / else ifブロックが再び失われます。







画像







読者は、 https//jsperf.com/shexpmatch-vs-host-string-vs-dnsdomainisで環境のテストを繰り返すことができます。







上記に基づき、IE11をテストすると根本的に反対の結果が得られますが、ifステートメントまたはif + orを使用する方が良いと結論付けます。 おそらくswitchステートメントを使用することをお勧めしますが、私はすでにこの夜の終わりを深夜に終えているので、尊敬されている読者にこのケースのテストを行います。







結論の代わりに



結論の代わりに、読者がこの小さな作業を最後まで習得してくれたことに感謝したいと思います。最適化のアドバイスとしてだけでなく、アクセスインフラストラクチャの操作における新しい知識やアイデアの源としても役立つことを心から願っています企業のインターネットへ。







便利なリンク



.pacファイルについてのシスコシステムズ

PACファイルで使用される機能を説明する便利なサイト

JavaScriptコードのパフォーマンスをテストするための便利なインターフェイスを提供するサイト

ここで、PACファイルのロジックを確認できます

PACファイルを含むJavaScriptコードをデバッグできる別のリソース








All Articles