分类 默认分类 下的文章

关于 Wireshark 分析 https 的 tcpdump 中的 Encrypted Alert

使用 Wireshark 分析 https 数据的时候, 尤其是分析网络为什么 reset 的时候, 经常看到有些数据行标注为: "Encrypted Alert", 紧接着就会看到连接主动/被动关闭或者 reset. 比如下图:
encryptedAlert.png

看到这 2 个单词, 我们很自然想到是不是加密过程出了什么问题? 为什么它提示 Alert? 今天我们具体去研究一下, 这个 "Encrypted Alert" 到底是什么, 跟连接断掉有什么关系?

首先, 我们研究一下这个 tcp 包的数据, 从下图可以看到, 它其实是传输层的数据, 没有应用层数据. 传输层的具体数据是: 它的内容类型(Content Type)是 Alert, 定义的 ID 是 21, 具体的 Alert Messge 就是: "Encrypted Alert". 从这里我们只能看到这个加密的会话出现了一个加密相关的告警, 没有其它可以告诉我们的.
ssl.png

另外, 在第一个截图中, 我们看到在 60 结尾的主机发 FIN 之前, 先发了一个 "Encrypted Alert" 消息, 接着发了 FIN. 之后 236 结尾的主机, 发了一个 "Encrypted Alert", 还没有发 FIN, 60 结尾的主机立马回了一个 RST.

TLS 协议

首先, TLS 协议根据内容类型(Content Type)有四种可能的记录(record)类型.
tlsP.png
根据 TLS 1.2 RFC5246, 这 4 种记录类型的编码分别是: 20, 21, 22, 23

enum {
          change_cipher_spec(20), alert(21), handshake(22),
          application_data(23), (255)
      } ContentType;

具体到 TLS 的 record, alert(21) 类型的数据, 只用到了 Content Type, TLS 协议大小版本号, 数据长度, 数据.
alert_record.png

对应我们上面截图中的数据:

  1. Content Type 是 21, 16 进制就是 0x15, 对应的是 Alert;
  2. 我们使用的版本号是 1.2, 对应的是 0x0303;
  3. 数据长度是 26 字节, 对应的 16 进制就是 0x001a;
  4. 对应的 payload 就是剩余的黄色里面的 26 字节的数据;
    alertPro.png

TLS 协议中的 Alert 数据

根据 TLS 1.2 RFC5246, Alert 的数据分为 AlertLevel 和 AlertDescription 2 部分. AlertLevel描述严重性: Warning 和 Fatal. AlertDescription 描述具体的 Alert 原因. 不过他们都是 enum 类型. 具体的数据结构是:

      enum { warning(1), fatal(2), (255) } AlertLevel;

      enum {
          close_notify(0),
          unexpected_message(10),
          bad_record_mac(20),
          decryption_failed_RESERVED(21),
          record_overflow(22),
          decompression_failure(30),
          handshake_failure(40),
          no_certificate_RESERVED(41),
          bad_certificate(42),
          unsupported_certificate(43),
          certificate_revoked(44),
          certificate_expired(45),
          certificate_unknown(46),
          illegal_parameter(47),
          unknown_ca(48),
          access_denied(49),
          decode_error(50),
          decrypt_error(51),
          export_restriction_RESERVED(60),
          protocol_version(70),
          insufficient_security(71),
          internal_error(80),
          user_canceled(90),
          no_renegotiation(100),
          unsupported_extension(110),
          (255)
      } AlertDescription;

      struct {
          AlertLevel level;
          AlertDescription description;
      } Alert;

那么有了上面比较全面的 Alert 的数据可能值, 我们能不能看出, 我们上面例子中具体的 Alert leve 和 alert decription 呢? 我们把看到的26 字节的数据和上面的任意一个对比, 都不能找到匹配的, 为什么呢?

根据上面的协议描述, 我们知道 Alert 的数据部分(level 和 description) 属于 payload 的部分, 而 payload 部分根据 RFC5246 是被加密和压缩的, 所以我们不能像找 header 部分的对应关系一样, 找到对应的数据.

Like other messages, alert messages are encrypted and compressed, as specified by the current connection state

如何找出具体的level 和 description 对应关系

我们知道, 可以通过 log sslkey 的方式, 把加密数据的关键key 记录下来, 然后让 Wireshark 解密的时候使用. 参考:
MAC 上解密 https 协议
Windows 上解密 https 协议

如果你使用 curl, 那就更方便了:

  1. 设置 key 文件的位置
    export SSLKEYLOGFILE=~/Downloads/keylog.log
  2. 开始抓包

    $ host www.tianxiaohui.com
    www.tianxiaohui.com has address 103.144.218.5
    $ sudo tcpdump host 103.144.218.5 -w ~/Download/tianxiaohui.pcap
  3. 访问 https 网站
    curl -vvv https://www.tianxiaohui.com/
  4. 设置 Wireshark
    菜单 -> 选项 -> 协议 -> TLS -> (Pre)-Master-Secret log filename 为我们上面的 key 文件

如此设置之后, 我们就看到了解密之后的 payload: 它的 level 是 warning, 对应 0x1, 它的 description 是 0x0, 对应 close_notify.
clear_msg.png

TLS 协议的结束消息

看到这里, 大家可能突然明白, 针对我们最后使用 curl 访问 https 的这个例子, 这里的 close_notify 原来就是 TLS 协议的结束消息, 告诉对方, 这个 TLS session 要结束了. 类似于 tcp 协议的 FIN 消息. 当然 Alert 类型的里面, 还有更多的不同的 description, 不过我们这里的正好是 close_notify.
这样印证了, 在 Wireshark 知道 key 之前, 它根本无法知道具体的 alert 是什么. 所以, 我们仅仅根据 "Encrypted Alert" 这个消息, 也无法推断具体的 alert 是什么类型, 到底发生了什么.

参考:

  1. RFC5246 https://datatracker.ietf.org/doc/html/rfc5246#section-6.2.1
  2. https://hpbn.co/transport-layer-security-tls/
  3. https://slideplayer.com/slide/8107590/
  4. https://www.openssl.org/docs/manmaster/man3/SSL_shutdown.html

kubectl 常见命令

官方 kubectl 参考在这里: https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands

有关 Cluster 的

kubectl cluster-info
kubectl top pod
kubectl top node 
kubectl certificate
kubectl cordon
kubectl uncordon
kubectl drain
kubectl taint

有关 troubleshooting

kubectl describe # 比 get 得到更多信息
kubectl logs
kubectl attach 
kubectl exec
kubectl port-forward
kubectl proxy
kubectl cp
kubectl auth can-i list deployments --all-namespaces

有关 api-resource

kubectl api-resources //列出所有 resource 类型
kubectl explain pods
kubectl explain pod.spec
kubectl explain pod.spec.containers.securityContext
kubectl get pod -n myns --cluster clusterName
kubectl get pod -n myns --context clusterName

create resource

# kubectl apply 用于创建或更新资源,适合持续部署和配置管理。
# kubectl create 仅用于创建新资源,如果资源已经存在,命令将失败。
tess kubectl create -f FILENAME [options]
tess kubectl apply (-f FILENAME | -k DIRECTORY) [options]

关于 Linux poll 的 timeout 参数的解释

最近研究 JDK 和 Netty 里面 socket timeout 的实现, 代码层面从 Java 代码一直追踪到 Linux 上的系统调用 poll. 当查看 poll 的手册的时候, 注意到一个不正常的描述.

首先, 通过 google 找到的是这个手册: https://linux.die.net/man/2/poll. 这个手册里面有关于 poll 的 timeout 参数的描述是:

The timeout argument specifies the minimum number of milliseconds that poll() will block.

注意, 它使用的是 "minimum", 那么对于正数的 timeout 值, 我可以有这些可能的理解:

  1. 不管有没有感兴趣的事件发生, 我最少必须等 timeout 的毫秒数;
  2. 在 timeout 值的时间窗口内, 有感兴趣的事情发生, 就直接返回, 若没有, 最少等 minimum 毫秒数;
    那么, 对于以上不管哪种理解, 最少的等待时间是 timeout 毫秒数, 那么最大的等待时间呢? 如果在 timeout 毫秒数内么有感兴趣的事件发生, 要等多久呢?

怀着这个问题, 我又返回去看 JDK 里的代码:
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/windows/native/java/net/SocketInputStream.c#l101
还是无法理解.

于是重新 google 搜索, 找到了这个问答:
https://stackoverflow.com/questions/529975/what-does-poll-do-with-a-timeout-of-0
pollMan.png
回答里面明显表明这是最大等待时间, 于是重新找另外的 Linux man page:
https://man7.org/linux/man-pages/man2/poll.2.html

The timeout argument specifies the number of milliseconds that poll() should block waiting for a file descriptor to become ready.

这里的意思, 就没有任何歧义了, 就是最大等待时间.

google search Operators 谷歌搜索操作符

  1. 限定搜索结果在某个或某些站点 -> 使用 site:

    site:github.com  
    site:*.edu
  2. 完全匹配多个字符 -> 使用双引号 ""

    "Steve Jobs"
  3. 结果不包含某些字符 -> 使用减号 -

    Socket -network
  4. 模糊匹配 -> 使用星号 *

    steve * apple
  5. 或者 -> 使用 or 或 |

    steve or gates
  6. 词典 翻译 -> 使用 define:

    define:star
  7. 返回最新缓存的 -> 使用cache:

    cache:ebay.com
  8. 特定文件类型 -> 使用 filetype: 或 ext:

    Distributed Systems, 3rd Edition filetype:pdf
  9. 搜索相关站点 -> 使用 related:

    related:github.com
  10. 搜索关键字在标题, url, 文本, 超链接 -> intitle: inurl: intext: inanchor:

    intitle:star
    inurl:star
    intext:star
  11. 搜索关键字全在标题, url, 文本, 超链接 -> allintitle: allinurl: allintext: allinanchor:

    allintitle:star life water
    allinurl:star life water
    allintext:star life water
  12. 多个条件组合 -> 使用括号

    (steve or jobs) rich