squidでBAISC認証付きフォワードプロキシを構成する

# 初めに

squidでフォワードプロキシ・BASIC認証・ログ出力の機能を試してみたメモ。
＃いずれリバースプロキシ・管理コンソール・squid client・telnetの中継等の機能も試したい

まずは以下でプロキシサーバにsquidを導入。

```sh
yum install squid 
systemctl start squid
systemctl status squid
systemctl reload squid # 定義更新時
```


# 概要

自宅→プロキシサーバ(squid)→インターネット　の構成を考える。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523824/143f6aac-7ab2-eb2a-a86d-eaf422ffd1ac.png)


※通信先にはグローバルIPを返してくれるサーバたちを利用させていただく

https://qiita.com/kanpou0108/items/734b947f5a95109e7bb9



プロキシに認証がついていて、かつアクセス先へブラックリスト的に制限をかけられるとプロキシっぽい、ということで、

* プロキシにBASIC認証を導入し

* 以下のルールに沿ってアクセス許可設定を行い、

  * ブラックリストへ登録されているサイトへの通信を遮断(今回は`inet-ip.info`への通信を遮断)

  * 自宅からのアクセスである場合に(= 送信元グローバルIPが自宅のものである場合に)、インターネットへ出ることを許可する

* 時刻の入ったアクセスログを出力する

を実現するsquidの設定を入れる。実際にsquid.confに設定した内容が以下。追記した箇所を★で記載。

```sh
[root@my-instance squid]# cat squid.conf
#
# Recommended minimum configuration:
#

# Example rule allowing access from your local networks.
# Adapt to list your (internal) IP networks from where browsing
# should be allowed
acl localnet src 10.0.0.0/8     # RFC1918 possible internal network
acl localnet src 172.16.0.0/12  # RFC1918 possible internal network
acl localnet src 192.168.0.0/16 # RFC1918 possible internal network
acl localnet src fc00::/7       # RFC 4193 local private network range
acl localnet src fe80::/10      # RFC 4291 link-local (directly plugged) machines

acl SSL_ports port 443
acl Safe_ports port 80          # http
acl Safe_ports port 21          # ftp
acl Safe_ports port 443         # https
acl Safe_ports port 210         # wais
acl Safe_ports port 1025-65535  # unregistered ports
acl Safe_ports port 280         # http-mgmt
acl Safe_ports port 488         # gss-http
acl Safe_ports port 591         # filemaker
acl Safe_ports port 777         # multiling http
acl CONNECT method CONNECT

# ★manually add
acl myhome src XXX.XXX.XXX.XXX/32    # ★自宅のグローバルIPに一致するか？のaclを定義
acl dst_blacklist dstdomain "/etc/squid/acl/blacklist"  #★ブラックリストに登録されたURLか？のaclを定義

# ★認証関連の設定
### ★NCSA方式でBASIC認証を行う、データソースは.htpasswd 
auth_param basic program /usr/lib64/squid/basic_ncsa_auth /etc/squid/.htpasswd
acl password_authentication proxy_auth REQUIRED # ★password_authenticationの名前で、認証がOKか？のaclを定義

#
# Recommended minimum Access Permission configuration:
#
# Deny requests to certain unsafe ports
http_access deny !Safe_ports

# Deny CONNECT to other than secure SSL ports
http_access deny CONNECT !SSL_ports

# Only allow cachemgr access from localhost
http_access allow localhost manager
http_access deny manager

# We strongly recommend the following be uncommented to protect innocent
# web applications running on the proxy server who think the only
# one who can access services on "localhost" is a local user
#http_access deny to_localhost

#
# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
#

# ★manually add
http_access deny !password_authentication # ★認証を通過していない通信は拒否
http_access deny dst_blacklist # ★ブラックリストに入っている通信も拒否
http_access allow myhome password_authentication !dst_blacklist 
# ↑ ★認証を通過・ブラックリストにも登録なし、かつ自宅からの通信のみ許可

### 以下5行はデフォルトで入っていた定義だが不要なためコメントアウト
# Example rule allowing access from your local networks.
# Adapt localnet in the ACL section to list your (internal) IP networks
# from where browsing should be allowed
# http_access allow localnet
# http_access allow localhost


# And finally deny all other access to this proxy
http_access deny all #それ以外はすべて拒否

# Squid normally listens to port 3128
http_port 3128

# Uncomment and adjust the following to add a disk cache directory.
#cache_dir ufs /var/spool/squid 100 16 256

# Leave coredumps in the first cache dir
coredump_dir /var/spool/squid

#
# Add any of your own refresh_pattern entries above these.
#
refresh_pattern ^ftp:           1440    20%     10080
refresh_pattern -i (/cgi-bin/|\?) 0     0%      0
refresh_pattern .               0       20%     4320

### ★manually add
debug_options ALL,1 28,9 #aclのみログレベルを最大(9)に
logformat combined %>a %ui %un [%tl] "%rm %ru HTTP/%rv" %Hs %<st "%{Referer}>h" "%{User-Agent}>h" %Ss:%Sh
access_log /var/log/squid/access.log combined # 時刻を記録できるようにログ出力を定義
```

ブラックリストの設定は以下。

```sh
[root@my-instance squid]# cat /etc/squid/acl/blacklist
inet-ip.info
```

単に宛先URLを書くだけで足りる。詳細に設定したい場合、acltypeに`dstdomain`ではなく`url_regex`を使うとよい。

* どちらも`How to block YouTube Videos` に例が載っている
  * https://wiki.squid-cache.org/ConfigExamples/Streams/YouTube



# 通信許可の設定(`acl`, `http_access`)

* ①判定条件を`acl <自分で名付けた判定条件名> <squidが用意しているaclタイプ> <引数(具体的な判定条件)>`という形で定義する
  * if文の条件だけ定義するイメージ。
  * 例えば`acl myhome src XXX.XXX.XXX.XXX/32`は「`src`が`XXX.XXX.XXX.XXX/32`であること」を`myhome`という名前で定義。
  * 引数に直接書くか(`acl aclname acltype argument ...` )、もしくは引数の内容をファイルに書いて指定するか`acl aclname acltype "file" ...`と表現される (https://www.squid-cache.org/Doc/config/acl/ より)
  * 上記の例では、ソースIPの制限は前者で、ブラックリストの指定は後者で行っている。
* ②判定条件に合致した通信を許可/遮断する宣言を行う
  * 「if <acl条件> then allow/deny」を書いているイメージ。
  * 例えば`http_access allow myhome` で、上記のmyhomeの条件に合致する通信を許可する。
  * これを順々に

```sh
http_access deny dst_blacklist   # if <acl条件1> then deny
http_access allow myhome         # if <acl条件2> then allow
```

といった調子で書いていき、上から順になめていって最初に一致するルールがあった時点でallow/denyが確定する。（それ以降の行は読まない）

一般的な記載順として、

```sh
http_access deny <拒否したいacl1>
http_access deny <拒否したいacl2>
...
http_access allow <許可したいacl1>
http_access allow <許可したいacl2>
...

http_access deny all
```

と書くのが見通しが立ちやすいか。if elif elseの文を提供してくれればもっと柔軟に書けるのに・・・とも思うが、逆に文法が原始的なおかげで平易な設定を入れるように考えることになり、そういう意味では有効なのかもしれない。



実際上記の設定も、ほぼそのような記載としている。（デフォルトで入っているmanagerのアクセスのみ例外があるが）以下は設定だけを抜きだしたもの。

```sh
http_access deny !Safe_ports # 変なポートへのアクセスを禁止
http_access deny CONNECT !SSL_ports # 変なポートへのアクセスを禁止
http_access allow localhost manager # マネージャーへのアクセスは
http_access deny manager            # →localhostからのみとする
http_access deny !password_authentication # 認証を通過していない通信は拒否
http_access deny dst_blacklist # ブラックリストに入っている通信も拒否
http_access allow myhome password_authentication !dst_blacklist # 認証を通過・ブラックリストにも登録なし、かつ自宅からの通信のみ許可
http_access deny all #それ以外はすべて拒否
```



squidの設定は

* 公式のreference を見るか
  * http://www.squid-cache.org/Doc/config/
* 公式のexamplesから似ているものを探すのも手。
  * https://wiki.squid-cache.org/ConfigExamples/
  * 上記の「特定のURLだけ拒否する」は、以下の`How to block YouTube Videos`の例が参考になる。
    * https://wiki.squid-cache.org/ConfigExamples/Streams/YouTube





# BASIC認証

BASIC認証を導入するにあたり、

* ①BASIC認証用のパスワードファイルを作成し、ユーザーを追加
* ②squidで、上記パスワードファイルを指定してBASIC認証を行う旨を追加

する必要がある。



### ①BASIC認証用のパスワードファイルを作成し、ユーザーを追加

するための設定が以下。apacheのツールに含まれる`htpasswd`というツールを利用して、BASIC認証用のファイルを作成する。

* `-c`でcreate new fileの意味。ユーザ追加時は`-c`をつけないように。（追加時にも`-c`をつけてしまうとファイルが上書きされてしまう）
* デフォルトではハッシュ関数としてMD5が利用される(`-m`)。他にもbcrypt(`-B`)、crypt(`-d`)、SHA(`-s`)、プレーン保存(`-p`)等指定できる
  * htpasswdのオプションの解説は以下に詳しい
    * https://qiita.com/masakuni-ito/items/3d951035884184632b99

```sh
### htpasswdが含まれるhttp-toolsをインストール
[root@my-instance squid]# yum install httpd-tools

# ユーザー：alphajinseiを作成
[root@my-instance squid]# htpasswd -c /etc/squid/.htpasswd alphajinsei
New password:
Re-type new password:
Adding password for user alphajinsei

# .htpasswdが新規作成され、alphajinseiのエントリが記載される
[root@my-instance squid]# cat /etc/squid/.htpasswd
alphajinsei:$apr1$6Ns6bl75$sq3K1LpRfmmkbsUcx4ZEG.

# 認証できるか確認
[root@my-instance squid]# htpasswd -v .htpasswd alphajinsei
Enter password:
Password for user alphajinsei correct.
```







### ②squidで、上記パスワードファイルを指定してBASIC認証を行う旨を追加

する設定は`squid.conf`の以下に相当。

```sh
### manually add 　★BASIC認証の設定
auth_param basic program /usr/lib64/squid/basic_ncsa_auth /etc/squid/.htpasswd
acl password proxy_auth REQUIRED

http_access deny !password_authentication # 認証を通過していない通信は拒否
http_access allow myhome password_authentication !dst_blacklist # 認証を通過していて、かつ他条件も満たす場合に通信を許可
```

* `auth_param basic program /usr/lib64/squid/basic_ncsa_auth /etc/squid/.htpasswd`で、
  * 認証方式として、squidが用意しているbasic認証のプログラム`/usr/lib64/squid/basic_ncsa_auth`を利用して
  * データソースとして、`/etc/squid/.htpasswd`をBASIC認証のパスワードファイルとして利用する　を宣言する。
* `acl password proxy_auth REQUIRED`で`password`という名前の"認証を強制するacl"を定義し、
* `http_access allow password`で認証を突破したアクセスのみ許可する

という方式。



※上記のNCSA式のbasic認証以外にも、digest認証等も利用可能で、認証のデータソースもパスワードファイル以外にLDAP・mysqlデータベース等を利用可能。以下がデフォルトでインストールされている。

```sh
[root@my-instance ~]# ll /usr/lib64/squid/ | grep auth
-rwxr-xr-x. 1 root root  5399  4月 12  2024 basic_db_auth
-rwxr-xr-x. 1 root root 11360  4月 12  2024 basic_getpwnam_auth
-rwxr-xr-x. 1 root root 23768  4月 12  2024 basic_ldap_auth
-rwxr-xr-x. 1 root root  5502  4月 12  2024 basic_msnt_multi_domain_auth
-rwxr-xr-x. 1 root root 24024  4月 12  2024 basic_ncsa_auth
-rwxr-xr-x. 1 root root 15488  4月 12  2024 basic_nis_auth
-rwxr-xr-x. 1 root root 19672  4月 12  2024 basic_pam_auth
-rwxr-xr-x. 1 root root  2975  4月 12  2024 basic_pop3_auth
-rwxr-xr-x. 1 root root 20056  4月 12  2024 basic_radius_auth
-rwxr-xr-x. 1 root root 15456  4月 12  2024 basic_sasl_auth
-rwxr-xr-x. 1 root root 15544  4月 12  2024 basic_smb_auth
-rwxr-xr-x. 1 root root  2657  4月 12  2024 basic_smb_auth.sh
-rwxr-xr-x. 1 root root 41504  4月 12  2024 basic_smb_lm_auth
-rwxr-xr-x. 1 root root 32192  4月 12  2024 digest_edirectory_auth
-rwxr-xr-x. 1 root root 24104  4月 12  2024 digest_file_auth
-rwxr-xr-x. 1 root root 28016  4月 12  2024 digest_ldap_auth
-rwxr-xr-x. 1 root root 44672  4月 12  2024 negotiate_kerberos_auth
-rwxr-xr-x. 1 root root 15656  4月 12  2024 negotiate_kerberos_auth_test
-rwxr-xr-x. 1 root root 23840  4月 12  2024 ntlm_fake_auth
-rwxr-xr-x. 1 root root 63096  4月 12  2024 ntlm_smb_lm_auth
```


メモ：
* 認証方式：
  * basic認証
    * ID/PWを平文(正確にはbase64エンコーディング)でやり取りする方式
  * digest認証
    * 通信の最初にサーバがランダム文字列(ソルトになる文字列)をクライアントに送り、クライアントは認証情報にソルトを付加したしたうえでハッシュ化してサーバへ送信する方式。チャレンジレスポンス方式とも。
  * kerberos認証：
    * チケットを発行してSSOを実現する認証方式。
* 認証のデータソース
  * パスワードファイル：
    * 上記の.htpasswdというファイルを利用する方式など。今回はこれ。
    * {認証方式：BASIC認証, データソース：パスワードファイル}の例：https://wiki.squid-cache.org/ConfigExamples/Authenticate/Ncsa
  * LDAP：
    * ディレクトリサービスを利用した認証
    * {認証方式：BASIC認証, データソース：LDAP}の例：https://wiki.squid-cache.org/ConfigExamples/Authenticate/Ldap
  * データベース
    * {認証方式：BASIC認証, データソース：MySQL}の例：https://wiki.squid-cache.org/ConfigExamples/Authenticate/Mysql





### ログの設定

ログの設定は以下を参考に追加。

https://dk521123.hatenablog.com/entry/2024/02/01/000000

```sh
debug_options ALL,1 28,9
logformat combined %>a %ui %un [%tl] "%rm %ru HTTP/%rv" %Hs %<st "%{Referer}>h" "%{User-Agent}>h" %Ss:%Sh
access_log /var/log/squid/access.log combined
```

* デバッグオプションの指定：
  * `ALL`がすべてのデバッグログのログレベルを1(最低限)に指定
  * 28(acl)のみログレベルを9(最大)まで指定
  * デバッグログはデフォルトで`/var/log/squid/cache.log`へ出力される。
* `logformat ...`で`combined`なる名前のログフォーマットを定義。`[tl]`でリクエストの時刻を出している。
  * その次の行で、「access.logに`combined`というフォーマットでログを出力」するように指定。
  * ログフォーマットの詳細は → https://www.squid-cache.org/Doc/config/logformat/



### 動作確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1523824/3e1d000d-a5ef-c1b3-0159-a81c148536fc.png)

①②③の順に確認する。③は割愛。

### ①自宅からhttpbin.org/ipにアクセス

プロキシにID/PWを正しく指定した場合、`http_access allow myhome password_authentication !dst_blacklist # 認証を通過・ブラックリストにも登録なし、かつ自宅からの通信のみ許可` を通過して200 OKで結果が返ってくる。

```sh
PS > curl.exe --proxy http://alphajinsei:password@YYY.YYY.YYY.YYY:3128 httpbin.org/ip -v
*   Trying YYY.YYY.YYY.YYY:3128...
* Connected to YYY.YYY.YYY.YYY (YYY.YYY.YYY.YYY) port 3128
* Proxy auth using Basic with user 'alphajinsei'
> GET http://httpbin.org/ip HTTP/1.1
> Host: httpbin.org
> Proxy-Authorization: Basic YWxwaGFqaW5zZWk6cGFzc3dvcmQ=
> User-Agent: curl/8.9.1
> Accept: */*
> Proxy-Connection: Keep-Alive
>
* Request completely sent off
< HTTP/1.1 200 OK
< Date: Mon, 04 Nov 2024 15:10:01 GMT
< Content-Type: application/json
< Content-Length: 49
< Server: gunicorn/19.9.0
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Credentials: true
< X-Cache: MISS from my-instance
< X-Cache-Lookup: MISS from my-instance:3128
< Via: 1.1 my-instance (squid/3.5.20)
< Connection: keep-alive
<
{
  "origin": "XXX.XXX.XXX.XXX, YYY.YYY.YYY.YYY"
}
* Connection #0 to host YYY.YYY.YYY.YYY left intact
```

アクセスログにも200で出力されている

```
[root@my-instance squid]# tail -f  /var/log/squid/access.log
XXX.XXX.XXX.XXX - alphajinsei [05/Nov/2024:00:09:53 +0900] "GET http://httpbin.org/ip HTTP/1.1" 200 391 "-" "curl/8.9.1" TCP_MISS:HIER_DIRECT
```





逆に誤ったID/PWを指定した場合、`http_access deny !password_authentication # 認証を通過していない通信は拒否`に引っかかって想定通りsquidが`407 Proxy Authentication Required`エラーを返す。

```sh
PS > curl.exe --proxy http://alphajinsei:wrongpassword@YYY.YYY.YYY.YYY:3128 httpbin.org/ip -v
*   Trying YYY.YYY.YYY.YYY:3128...
* Connected to YYY.YYY.YYY.YYY (YYY.YYY.YYY.YYY) port 3128
* Proxy auth using Basic with user 'alphajinsei'
> GET http://httpbin.org/ip HTTP/1.1
> Host: httpbin.org
> Proxy-Authorization: Basic YWxwaGFqaW5zZWk6d3JvbmdwYXNzd29yZA==
> User-Agent: curl/8.9.1
> Accept: */*
> Proxy-Connection: Keep-Alive
>
* Request completely sent off
< HTTP/1.1 407 Proxy Authentication Required
< Server: squid/3.5.20
< Mime-Version: 1.0
< Date: Mon, 04 Nov 2024 15:14:11 GMT
< Content-Type: text/html;charset=utf-8
< Content-Length: 3655
< X-Squid-Error: ERR_CACHE_ACCESS_DENIED 0
< Vary: Accept-Language
< Content-Language: en
* Authentication problem. Ignoring this.
< Proxy-Authenticate: Basic realm="Squid proxy-caching web server"
< X-Cache: MISS from my-instance
< X-Cache-Lookup: NONE from my-instance:3128
< Via: 1.1 my-instance (squid/3.5.20)
< Connection: keep-alive
<
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>
<meta type="copyright" content="Copyright (C) 1996-2016 The Squid Software Foundation and contributors">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>ERROR: Cache Access Denied</title>
<style type="text/css"><!--
(略)
 --></style>
</head><body id=ERR_CACHE_ACCESS_DENIED>
<div id="titles">
<h1>ERROR</h1>
<h2>Cache Access Denied.</h2>
</div>
<hr>

<div id="content">
<p>The following error was encountered while trying to retrieve the URL: <a href="http://httpbin.org/ip">http://httpbin.org/ip</a></p>

<blockquote id="error">
<p><b>Cache Access Denied.</b></p>
</blockquote>

<p>Sorry, you are not currently allowed to request http://httpbin.org/ip from this cache until you have authenticated yourself.</p>

<p>Please contact the <a href="mailto:root?subject=CacheErrorInfo%20-%20ERR_CACHE_ACCESS_DENIED&amp;body=CacheHost%3A%20my-instance%0D%0AErrPage%3A%20ERR_CACHE_ACCESS_DENIED%0D%0AErr%3A%20%5Bnone%5D%0D%0AAuth%20ErrMsg%3A%20Wrong%20password%0D%0ATimeStamp%3A%20Mon,%2004%20Nov%202024%2015%3A14%3A11%20GMT%0D%0A%0D%0AClientIP%3A%20XXX.XXX.XXX.XXX%0D%0A%0D%0AHTTP%20Request%3A%0D%0AGET%20%2Fip%20HTTP%2F1.1%0AProxy-Authorization%3A%20Basic%20YWxwaGFqaW5zZWk6d3JvbmdwYXNzd29yZA%3D%3D%0D%0AUser-Agent%3A%20curl%2F8.9.1%0D%0AAccept%3A%20*%2F*%0D%0AProxy-Connection%3A%20Keep-Alive%0D%0AHost%3A%20httpbin.org%0D%0A%0D%0A%0D%0A">cache administrator</a> if you have difficulties authenticating yourself.</p>

<br>
</div>

<hr>
<div id="footer">
<p>Generated Mon, 04 Nov 2024 15:14:11 GMT by my-instance (squid/3.5.20)</p>
<!-- ERR_CACHE_ACCESS_DENIED -->
</div>
</body></html>
* Connection #0 to host YYY.YYY.YYY.YYY left intact
```





### ②自宅からinet-ip.infoにアクセス

`http_access deny dst_blacklist # ブラックリストに入っている通信も拒否`に引っかかってsquidがエラーを返す。この場合は`403 Forbidden`になる様子。

```sh
PS > curl.exe --proxy http://alphajinsei:password@YYY.YYY.YYY.YYY:3128 http://inet-ip.info -v
*   Trying YYY.YYY.YYY.YYY:3128...
* Connected to YYY.YYY.YYY.YYY (YYY.YYY.YYY.YYY) port 3128
* Proxy auth using Basic with user 'alphajinsei'
> GET http://inet-ip.info/ HTTP/1.1
> Host: inet-ip.info
> Proxy-Authorization: Basic YWxwaGFqaW5zZWk6cGFzc3dvcmQ=
> User-Agent: curl/8.9.1
> Accept: */*
> Proxy-Connection: Keep-Alive
>
* Request completely sent off
< HTTP/1.1 403 Forbidden
< Server: squid/3.5.20
< Mime-Version: 1.0
< Date: Mon, 04 Nov 2024 15:10:28 GMT
< Content-Type: text/html;charset=utf-8
< Content-Length: 3581
< X-Squid-Error: ERR_ACCESS_DENIED 0
< Vary: Accept-Language
< Content-Language: en
< X-Cache: MISS from my-instance
< X-Cache-Lookup: NONE from my-instance:3128
< Via: 1.1 my-instance (squid/3.5.20)
< Connection: keep-alive
<
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>
<meta type="copyright" content="Copyright (C) 1996-2016 The Squid Software Foundation and contributors">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>ERROR: The requested URL could not be retrieved</title>
<style type="text/css"><!--
(略)
 --></style>
</head><body id=ERR_ACCESS_DENIED>
<div id="titles">
<h1>ERROR</h1>
<h2>The requested URL could not be retrieved</h2>
</div>
<hr>

<div id="content">
<p>The following error was encountered while trying to retrieve the URL: <a href="http://inet-ip.info/">http://inet-ip.info/</a></p>

<blockquote id="error">
<p><b>Access Denied.</b></p>
</blockquote>

<p>Access control configuration prevents your request from being allowed at this time. Please contact your service provider if you feel this is incorrect.</p>

<p>Your cache administrator is <a href="mailto:root?subject=CacheErrorInfo%20-%20ERR_ACCESS_DENIED&amp;body=CacheHost%3A%20my-instance%0D%0AErrPage%3A%20ERR_ACCESS_DENIED%0D%0AErr%3A%20%5Bnone%5D%0D%0ATimeStamp%3A%20Mon,%2004%20Nov%202024%2015%3A10%3A28%20GMT%0D%0A%0D%0AClientIP%3A%20XXX.XXX.XXX.XXX%0D%0A%0D%0AHTTP%20Request%3A%0D%0AGET%20%2F%20HTTP%2F1.1%0AProxy-Authorization%3A%20Basic%20YWxwaGFqaW5zZWk6cGFzc3dvcmQ%3D%0D%0AUser-Agent%3A%20curl%2F8.9.1%0D%0AAccept%3A%20*%2F*%0D%0AProxy-Connection%3A%20Keep-Alive%0D%0AHost%3A%20inet-ip.info%0D%0A%0D%0A%0D%0A">root</a>.</p>
<br>
</div>

<hr>
<div id="footer">
<p>Generated Mon, 04 Nov 2024 15:10:28 GMT by my-instance (squid/3.5.20)</p>
<!-- ERR_ACCESS_DENIED -->
</div>
</body></html>
* Connection #0 to host YYY.YYY.YYY.YYY left intact
```






# 補足：デバッグログの見方

今回は`/var/log/squid/cache.log`に詳細なデバッグログを表示させているので、条件文がどのように評価されていったかを追うことができる。(＝これを見ないとわからないぐらい苦戦した）

### 通信が遮断されたときのログ

以下は自宅から` curl.exe --proxy http://alphajinsei:password@YYY.YYY.YYY.YYY:3128 http://inet-ip.info -v`を飛ばしてブラックリストで遮断されたときのログ。

* checking http_access#1,2...の通り、http_accessで記載された条件文を上から順に確認していく様子が見える。
* http_accessに紐づくaclの真偽を都度確認しており、1:True, 0:false で判定している。
  * 例えばhttp_access#1で利用しているacl:`!Safe_ports`は`Safe_ports = 1`で判定されており、「特定のsafe_portを利用している」が真と判定され、結果http_access#1 `deny !Safe_ports`は`http_access#1 = 0`、つまりこの条件文は発動しない、denyされない、と判断されている。
* ` checked: password_authentication = 1`、`checked: http_access#5 = 0`とあることから、`http_access deny !password_authentication`は発動せず、認証が通過していることがわかる
* その次の`dst_blacklist = 1`、`http_access#6 = 1`であることから、blacklistの判定`http_access deny dst_blacklist`が発動、通信は遮断される。
* 直後の`markFinished: 0x561a0a37d638 answer DENIED for match`の記載が重要。この記載が最終的なsquidの判断結果を表しており、この通信はdenyされたことがわかる。



```sh
[root@my-instance squid]# tail -f  /var/log/squid/cache.log
2024/11/05 00:16:45.619 kid1| 28,4| Eui48.cc(178) lookup: id=0x561a0b18c944 query ARP table
2024/11/05 00:16:45.620 kid1| 28,4| Eui48.cc(222) lookup: id=0x561a0b18c944 query ARP on each interface (200 found)
2024/11/05 00:16:45.620 kid1| 28,4| Eui48.cc(228) lookup: id=0x561a0b18c944 found interface lo
2024/11/05 00:16:45.620 kid1| 28,4| Eui48.cc(228) lookup: id=0x561a0b18c944 found interface ens3
2024/11/05 00:16:45.620 kid1| 28,4| Eui48.cc(237) lookup: id=0x561a0b18c944 looking up ARP address for XXX.XXX.XXX.XXX on ens3
2024/11/05 00:16:45.621 kid1| 28,4| Eui48.cc(228) lookup: id=0x561a0b18c944 found interface docker0
2024/11/05 00:16:45.621 kid1| 28,4| Eui48.cc(237) lookup: id=0x561a0b18c944 looking up ARP address for XXX.XXX.XXX.XXX on docker0
2024/11/05 00:16:45.622 kid1| 28,4| Eui48.cc(228) lookup: id=0x561a0b18c944 found interface br-8da257b9aef5
2024/11/05 00:16:45.622 kid1| 28,4| Eui48.cc(237) lookup: id=0x561a0b18c944 looking up ARP address for XXX.XXX.XXX.XXX on br-8da257b9aef5
2024/11/05 00:16:45.622 kid1| 28,4| Eui48.cc(228) lookup: id=0x561a0b18c944 found interface br-ea467fa54707
2024/11/05 00:16:45.622 kid1| 28,4| Eui48.cc(237) lookup: id=0x561a0b18c944 looking up ARP address for XXX.XXX.XXX.XXX on br-ea467fa54707
2024/11/05 00:16:45.623 kid1| 28,3| Eui48.cc(520) lookup: id=0x561a0b18c944 XXX.XXX.XXX.XXX NOT found
2024/11/05 00:16:45.623 kid1| 28,4| FilledChecklist.cc(66) ~ACLFilledChecklist: ACLFilledChecklist destroyed 0x7fffe5dcef30
2024/11/05 00:16:45.623 kid1| 28,4| Checklist.cc(197) ~ACLChecklist: ACLChecklist::~ACLChecklist: destroyed 0x7fffe5dcef30
2024/11/05 00:16:45.636 kid1| 28,3| Checklist.cc(70) preCheck: 0x561a0a37d638 checking slow rules
2024/11/05 00:16:45.636 kid1| 28,5| Acl.cc(138) matches: checking http_access
2024/11/05 00:16:45.637 kid1| 28,5| Checklist.cc(400) bannedAction: Action 'DENIED/0is not banned
2024/11/05 00:16:45.637 kid1| 28,5| Acl.cc(138) matches: checking http_access#1
2024/11/05 00:16:45.637 kid1| 28,5| Acl.cc(138) matches: checking !Safe_ports
2024/11/05 00:16:45.637 kid1| 28,5| Acl.cc(138) matches: checking Safe_ports
2024/11/05 00:16:45.637 kid1| 28,3| Acl.cc(158) matches: checked: Safe_ports = 1
2024/11/05 00:16:45.637 kid1| 28,3| Acl.cc(158) matches: checked: !Safe_ports = 0
2024/11/05 00:16:45.637 kid1| 28,3| Acl.cc(158) matches: checked: http_access#1 = 0
2024/11/05 00:16:45.637 kid1| 28,5| Checklist.cc(400) bannedAction: Action 'DENIED/0is not banned
2024/11/05 00:16:45.637 kid1| 28,5| Acl.cc(138) matches: checking http_access#2
2024/11/05 00:16:45.638 kid1| 28,5| Acl.cc(138) matches: checking CONNECT
2024/11/05 00:16:45.638 kid1| 28,3| Acl.cc(158) matches: checked: CONNECT = 0
2024/11/05 00:16:45.638 kid1| 28,3| Acl.cc(158) matches: checked: http_access#2 = 0
2024/11/05 00:16:45.638 kid1| 28,5| Checklist.cc(400) bannedAction: Action 'ALLOWED/0is not banned
2024/11/05 00:16:45.638 kid1| 28,5| Acl.cc(138) matches: checking http_access#3
2024/11/05 00:16:45.638 kid1| 28,5| Acl.cc(138) matches: checking localhost
2024/11/05 00:16:45.638 kid1| 28,9| Ip.cc(95) aclIpAddrNetworkCompare: aclIpAddrNetworkCompare: compare: XXX.XXX.XXX.XXX:61480/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff] (XXX.XXX.XXX.XXX:61480)  vs 127.0.0.1-[::]/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]
2024/11/05 00:16:45.638 kid1| 28,9| Ip.cc(95) aclIpAddrNetworkCompare: aclIpAddrNetworkCompare: compare: XXX.XXX.XXX.XXX:61480/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff] (XXX.XXX.XXX.XXX:61480)  vs [::1]-[::]/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]
2024/11/05 00:16:45.638 kid1| 28,9| Ip.cc(95) aclIpAddrNetworkCompare: aclIpAddrNetworkCompare: compare: XXX.XXX.XXX.XXX:61480/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff] (XXX.XXX.XXX.XXX:61480)  vs [::1]-[::]/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]
2024/11/05 00:16:45.638 kid1| 28,3| Ip.cc(539) match: aclIpMatchIp: 'XXX.XXX.XXX.XXX:61480' NOT found
2024/11/05 00:16:45.638 kid1| 28,3| Acl.cc(158) matches: checked: localhost = 0
2024/11/05 00:16:45.638 kid1| 28,3| Acl.cc(158) matches: checked: http_access#3 = 0
2024/11/05 00:16:45.638 kid1| 28,5| Checklist.cc(400) bannedAction: Action 'DENIED/0is not banned
2024/11/05 00:16:45.639 kid1| 28,5| Acl.cc(138) matches: checking http_access#4
2024/11/05 00:16:45.639 kid1| 28,5| Acl.cc(138) matches: checking manager
2024/11/05 00:16:45.639 kid1| 28,3| RegexData.cc(51) match: aclRegexData::match: checking 'http://inet-ip.info/'
2024/11/05 00:16:45.639 kid1| 28,3| RegexData.cc(62) match: aclRegexData::match: looking for '(^cache_object://)'
2024/11/05 00:16:45.639 kid1| 28,3| RegexData.cc(62) match: aclRegexData::match: looking for '(^https?://[^/]+/squid-internal-mgr/)'
2024/11/05 00:16:45.639 kid1| 28,3| Acl.cc(158) matches: checked: manager = 0
2024/11/05 00:16:45.639 kid1| 28,3| Acl.cc(158) matches: checked: http_access#4 = 0
2024/11/05 00:16:45.639 kid1| 28,5| Checklist.cc(400) bannedAction: Action 'DENIED/0is not banned
2024/11/05 00:16:45.639 kid1| 28,5| Acl.cc(138) matches: checking http_access#5
2024/11/05 00:16:45.639 kid1| 28,5| Acl.cc(138) matches: checking !password_authentication
2024/11/05 00:16:45.639 kid1| 28,5| Acl.cc(138) matches: checking password_authentication
2024/11/05 00:16:45.639 kid1| 28,8| Acl.cc(355) aclCacheMatchFlush: aclCacheMatchFlush called for cache 0x561a09f35578
2024/11/05 00:16:45.639 kid1| 28,3| AclProxyAuth.cc(119) checkForAsync: checking password via authenticator
2024/11/05 00:16:45.639 kid1| 28,4| Acl.cc(70) AuthenticateAcl: returning 2 sending credentials to helper.
2024/11/05 00:16:45.640 kid1| 28,3| Acl.cc(158) matches: checked: password_authentication = -1 async
2024/11/05 00:16:45.640 kid1| 28,3| Acl.cc(158) matches: checked: !password_authentication = -1 async
2024/11/05 00:16:45.640 kid1| 28,3| Acl.cc(158) matches: checked: http_access#5 = -1 async
2024/11/05 00:16:45.640 kid1| 28,3| Acl.cc(158) matches: checked: http_access = -1 async
2024/11/05 00:16:45.640 kid1| 28,5| InnerNode.cc(94) resumeMatchingAt: checking http_access at 4
2024/11/05 00:16:45.640 kid1| 28,5| Checklist.cc(400) bannedAction: Action 'DENIED/0is not banned
2024/11/05 00:16:45.640 kid1| 28,5| InnerNode.cc(94) resumeMatchingAt: checking http_access#5 at 0
2024/11/05 00:16:45.640 kid1| 28,5| InnerNode.cc(94) resumeMatchingAt: checking !password_authentication at 0
2024/11/05 00:16:45.640 kid1| 28,5| Acl.cc(138) matches: checking password_authentication
2024/11/05 00:16:45.640 kid1| 28,4| Acl.cc(333) cacheMatchAcl: ACL::cacheMatchAcl: cache hit on acl 'password_authentication' (0x561a0a38cf30)
2024/11/05 00:16:45.641 kid1| 28,3| Acl.cc(158) matches: checked: password_authentication = 1
2024/11/05 00:16:45.641 kid1| 28,3| InnerNode.cc(97) resumeMatchingAt: checked: !password_authentication = 0
2024/11/05 00:16:45.641 kid1| 28,3| InnerNode.cc(97) resumeMatchingAt: checked: http_access#5 = 0
2024/11/05 00:16:45.641 kid1| 28,5| Checklist.cc(400) bannedAction: Action 'DENIED/0is not banned
2024/11/05 00:16:45.641 kid1| 28,5| Acl.cc(138) matches: checking http_access#6
2024/11/05 00:16:45.641 kid1| 28,5| Acl.cc(138) matches: checking dst_blacklist
2024/11/05 00:16:45.641 kid1| 28,3| DomainData.cc(108) match: aclMatchDomainList: checking 'inet-ip.info'
2024/11/05 00:16:45.641 kid1| 28,3| DomainData.cc(113) match: aclMatchDomainList: 'inet-ip.info' found
2024/11/05 00:16:45.641 kid1| 28,3| Acl.cc(158) matches: checked: dst_blacklist = 1
2024/11/05 00:16:45.641 kid1| 28,3| Acl.cc(158) matches: checked: http_access#6 = 1
2024/11/05 00:16:45.641 kid1| 28,3| InnerNode.cc(97) resumeMatchingAt: checked: http_access = 1
2024/11/05 00:16:45.641 kid1| 28,3| Checklist.cc(63) markFinished: 0x561a0a37d638 answer DENIED for match
2024/11/05 00:16:45.641 kid1| 28,3| Checklist.cc(163) checkCallback: ACLChecklist::checkCallback: 0x561a0a37d638 answer=DENIED
2024/11/05 00:16:45.642 kid1| 28,5| Gadgets.cc(83) aclIsProxyAuth: aclIsProxyAuth: called for dst_blacklist
2024/11/05 00:16:45.642 kid1| 28,9| Acl.cc(99) FindByName: ACL::FindByName 'dst_blacklist'
2024/11/05 00:16:45.642 kid1| 28,5| Gadgets.cc(88) aclIsProxyAuth: aclIsProxyAuth: returning 0
2024/11/05 00:16:45.642 kid1| 28,8| Gadgets.cc(51) aclGetDenyInfoPage: got called for dst_blacklist
2024/11/05 00:16:45.642 kid1| 28,8| Gadgets.cc(70) aclGetDenyInfoPage: aclGetDenyInfoPage: no match
2024/11/05 00:16:45.642 kid1| 28,4| FilledChecklist.cc(66) ~ACLFilledChecklist: ACLFilledChecklist destroyed 0x7fffe5dced50
2024/11/05 00:16:45.642 kid1| 28,4| Checklist.cc(197) ~ACLChecklist: ACLChecklist::~ACLChecklist: destroyed 0x7fffe5dced50
2024/11/05 00:16:45.642 kid1| 28,4| FilledChecklist.cc(66) ~ACLFilledChecklist: ACLFilledChecklist destroyed 0x7fffe5dced50
2024/11/05 00:16:45.642 kid1| 28,4| Checklist.cc(197) ~ACLChecklist: ACLChecklist::~ACLChecklist: destroyed 0x7fffe5dced50
2024/11/05 00:16:45.642 kid1| 28,4| FilledChecklist.cc(66) ~ACLFilledChecklist: ACLFilledChecklist destroyed 0x561a0a37d638
2024/11/05 00:16:45.643 kid1| 28,4| Checklist.cc(197) ~ACLChecklist: ACLChecklist::~ACLChecklist: destroyed 0x561a0a37d638
2024/11/05 00:16:45.643 kid1| 28,3| Checklist.cc(70) preCheck: 0x7fffe5dcec20 checking fast ACLs
2024/11/05 00:16:45.643 kid1| 28,5| Acl.cc(138) matches: checking access_log /var/log/squid/access.log
2024/11/05 00:16:45.643 kid1| 28,5| Acl.cc(138) matches: checking (access_log /var/log/squid/access.log line)
2024/11/05 00:16:45.643 kid1| 28,3| Acl.cc(158) matches: checked: (access_log /var/log/squid/access.log line) = 1
2024/11/05 00:16:45.643 kid1| 28,3| Acl.cc(158) matches: checked: access_log /var/log/squid/access.log = 1
2024/11/05 00:16:45.643 kid1| 28,3| Checklist.cc(63) markFinished: 0x7fffe5dcec20 answer ALLOWED for match
2024/11/05 00:16:45.643 kid1| 28,4| FilledChecklist.cc(66) ~ACLFilledChecklist: ACLFilledChecklist destroyed 0x7fffe5dcec20
2024/11/05 00:16:45.643 kid1| 28,4| Checklist.cc(197) ~ACLChecklist: ACLChecklist::~ACLChecklist: destroyed 0x7fffe5dcec20
```


### 通信が許可されたときのログ

以下は通信が通る場合、`PS C:\Users\peinn> curl.exe --proxy http://alphajinsei:password@YYY.YYY.YYY.YYY:3128 httpbin.org/ip -v`を打鍵したときのログ出力。http_access#7、`allow myhome password_authentication !dst_blacklist `だけ抜き出しているが、

* 自宅からのアクセスである：`myhome = 1`
* 認証を通過している：`password_authentication = 1`
* ブラックリストに載っていない： `dst_blacklist = 0`

が満たされたためhttp_access#7の条件文が有効(`http_access#7 = 1`)と判定され、通信が許可(`markFinished: 0x561a0a37d638 answer ALLOWED for match`)されたことがわかる。
```sh
(前略)
2024/11/05 00:26:58.331 kid1| 28,5| Acl.cc(138) matches: checking http_access#7
2024/11/05 00:26:58.331 kid1| 28,5| Acl.cc(138) matches: checking myhome
2024/11/05 00:26:58.331 kid1| 28,9| Ip.cc(95) aclIpAddrNetworkCompare: aclIpAddrNetworkCompare: compare: XXX.XXX.XXX.XXX:61598/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff] (XXX.XXX.XXX.XXX:61598)  vs XXX.XXX.XXX.XXX-[::]/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]
2024/11/05 00:26:58.331 kid1| 28,3| Ip.cc(539) match: aclIpMatchIp: 'XXX.XXX.XXX.XXX:61598' found
2024/11/05 00:26:58.331 kid1| 28,3| Acl.cc(158) matches: checked: myhome = 1
2024/11/05 00:26:58.331 kid1| 28,5| Acl.cc(138) matches: checking password_authentication
2024/11/05 00:26:58.331 kid1| 28,4| Acl.cc(333) cacheMatchAcl: ACL::cacheMatchAcl: cache hit on acl 'password_authentication' (0x561a0a38cf30)
2024/11/05 00:26:58.331 kid1| 28,3| Acl.cc(158) matches: checked: password_authentication = 1
2024/11/05 00:26:58.331 kid1| 28,5| Acl.cc(138) matches: checking !dst_blacklist
2024/11/05 00:26:58.331 kid1| 28,5| Acl.cc(138) matches: checking dst_blacklist
2024/11/05 00:26:58.331 kid1| 28,3| DomainData.cc(108) match: aclMatchDomainList: checking 'httpbin.org'
2024/11/05 00:26:58.331 kid1| 28,3| DomainData.cc(113) match: aclMatchDomainList: 'httpbin.org' NOT found
2024/11/05 00:26:58.331 kid1| 28,3| Acl.cc(158) matches: checked: dst_blacklist = 0
2024/11/05 00:26:58.331 kid1| 28,3| Acl.cc(158) matches: checked: !dst_blacklist = 1
2024/11/05 00:26:58.332 kid1| 28,3| Acl.cc(158) matches: checked: http_access#7 = 1
2024/11/05 00:26:58.332 kid1| 28,3| Acl.cc(158) matches: checked: http_access = 1
2024/11/05 00:26:58.332 kid1| 28,3| Checklist.cc(63) markFinished: 0x561a0a37d638 answer ALLOWED for match
2024/11/05 00:26:58.332 kid1| 28,3| Checklist.cc(163) checkCallback: ACLChecklist::checkCallback: 0x561a0a37d638 answer=ALLOWED
2024/11/05 00:26:58.336 kid1| 28,4| FilledChecklist.cc(66) ~ACLFilledChecklist: ACLFilledChecklist destroyed 0x7fffe5dce290
2024/11/05 00:26:58.336 kid1| 28,4| Checklist.cc(197) ~ACLChecklist: ACLChecklist::~ACLChecklist: destroyed 0x7fffe5dce290
2024/11/05 00:26:58.336 kid1| 28,4| FilledChecklist.cc(66) ~ACLFilledChecklist: ACLFilledChecklist destroyed 0x7fffe5dce290
2024/11/05 00:26:58.336 kid1| 28,4| Checklist.cc(197) ~ACLChecklist: ACLChecklist::~ACLChecklist: destroyed 0x7fffe5dce290
2024/11/05 00:26:58.339 kid1| 28,4| FilledChecklist.cc(66) ~ACLFilledChecklist: ACLFilledChecklist destroyed 0x561a0a37d638
2024/11/05 00:26:58.339 kid1| 28,4| Checklist.cc(197) ~ACLChecklist: ACLChecklist::~ACLChecklist: destroyed 0x561a0a37d638
2024/11/05 00:26:58.340 kid1| 28,4| FilledChecklist.cc(66) ~ACLFilledChecklist: ACLFilledChecklist destroyed 0x7fffe5dce8b0
2024/11/05 00:26:58.340 kid1| 28,4| Checklist.cc(197) ~ACLChecklist: ACLChecklist::~ACLChecklist: destroyed 0x7fffe5dce8b0
2024/11/05 00:26:58.489 kid1| 28,4| FilledChecklist.cc(66) ~ACLFilledChecklist: ACLFilledChecklist destroyed 0x7fffe5dce970
2024/11/05 00:26:58.489 kid1| 28,4| Checklist.cc(197) ~ACLChecklist: ACLChecklist::~ACLChecklist: destroyed 0x7fffe5dce970
2024/11/05 00:26:58.640 kid1| 28,3| Checklist.cc(70) preCheck: 0x7fffe5dcebd0 checking fast ACLs
2024/11/05 00:26:58.640 kid1| 28,5| Acl.cc(138) matches: checking access_log /var/log/squid/access.log
2024/11/05 00:26:58.640 kid1| 28,5| Acl.cc(138) matches: checking (access_log /var/log/squid/access.log line)
2024/11/05 00:26:58.640 kid1| 28,3| Acl.cc(158) matches: checked: (access_log /var/log/squid/access.log line) = 1
2024/11/05 00:26:58.640 kid1| 28,3| Acl.cc(158) matches: checked: access_log /var/log/squid/access.log = 1
2024/11/05 00:26:58.640 kid1| 28,3| Checklist.cc(63) markFinished: 0x7fffe5dcebd0 answer ALLOWED for match
2024/11/05 00:26:58.641 kid1| 28,4| FilledChecklist.cc(66) ~ACLFilledChecklist: ACLFilledChecklist destroyed 0x7fffe5dcebd0
2024/11/05 00:26:58.641 kid1| 28,4| Checklist.cc(197) ~ACLChecklist: ACLChecklist::~ACLChecklist: destroyed 0x7fffe5dcebd0
```