@霏艺Faye
@霏艺Faye
图书管理员
关注的小组(4)
动态 帖子 468 评论 466 短评 0 收到的赞 221 送出的赞 3
  1. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    一点声明

    瞄了一眼2049的代码。。

    代码是golang写的,MVC架构。数据库是youdb,抛弃了ORM,将obj直接序列化存储到key -value的数据库。

    好处是不需要mybatis这样的orm框架了,坏处是很多复杂业务,代码写起来就很变态,而且性能很糟。

    youdb和leveldb一样,属于文件型数据库,同类是sqlite,但是sqlite是传统数据库,youdb是key-value数据库。

    ++++++++++++++

    话说这代码是真的轻量级啊,MVC分的也算清楚,内部实现也不复杂。

    说了这么多废话,就是觉得不喜欢这里的人,回家自己搭一个bbs自娱自乐也挺好的~

    我也用discuz搭过一个bbs,可惜被共产党封杀了

  2. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    如何讓chrome支持ESNI

    繼續查看ext_sni_add_clienthello函數

    發現CBB_add_bytes(&name, (const uint8_t *)ssl->hostname.get(),這行代碼,會對SNI賦值hostname

    也就是說,爲什麽我們通過wireshark抓包,可以明文看到自己訪問什麽網站,就是這行代碼造成的!

    GFW通過全網檢查ClientHello的SNI字段,來判斷你在訪問什麽網站!而且因爲是明文,所以GFW的工作很簡單,只要檢查你的TLS握手SNI字段,如果是敏感詞,就RST掉你的tcp連接。你就上不去了。品蔥就是這樣,所以上不去,需要開啓ESNI功能,就沒事了~

    代碼修改:

    1.增加一個ext,取名叫ESNI,參考SNI的實現,完成相關代碼

    2.移植火狐的esni加密代碼到boringssl,完成第一步的esni報文拼接

    3.編譯自己的boringssl庫,替換掉chrome自帶的boringssl

    4.chrome有自己dll校驗機制,你手動替換有點問題,好像跑不起來,得網上找下教程,學習如何替換chrome的boringssl

    別找我要代碼或者已經編譯好的dll !我要是寫好了,早提PR給chrome了~

    關於爲什麽不自己寫代碼完成剛才我説的這麽多事情:

    我翻墻的條件很糟糕,下載chrome的源碼,經常斷掉!失敗就得重新下載。至今沒有下載到chrome源碼。

    另外編譯環境配置非常複雜,我沒有那個功夫去完成這麽費時間的工作。老了啊,想當年自己花了3個星期,搭了Gentoo Linux,現在搭個chrome的編譯環境都覺得浪費時間

  3. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    如何讓chrome支持ESNI

    言歸正傳!

    我們講解Chrome了,chrome的TLS實現叫做BoringSSL,fork自著名的openSSL。

    開始講如何boringssl的代碼。

    翻開課本,boringssl\ssl\handshake_client.cc這個代碼。開始閲讀ssl_client_handshake

    對!ESNI是在客戶端發起握手的時候發送的!所以從握手開始讀起。

    找到do_start_connect這個函數!很多人覺得看著這個代碼,很嚇人。別怕,其實關鍵信息就i是ssl_write_client_hello這麽一行罷了。其他的都不重要~

    ssl_write_client_hello這個函數,什麽都不做,純粹拼報文而已!二進制級別拼寫,類似給一個struct賦值。

    我們就看ssl_add_clienthello_tlsext這個函數!因爲ESNI或者SNI都是放在ext字段。

    翻開課本 boringssl\ssl\t1_lib.cc 找到 ssl_add_clienthello_tlsext

      for (size_t i = 0; i < kNumExtensions; i++) {
        const size_t len_before = CBB_len(&extensions);
        if (!kExtensions[i].add_clienthello(hs, &extensions)) {
          OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
          ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
          return false;
        }
    

    意思是遍歷所有的ext,調用對應ext的add_clienthello函數,拼clienthello報文

    // kExtensions contains all the supported extensions.
    static const struct tls_extension kExtensions[] = {
      {
        TLSEXT_TYPE_server_name,
        NULL,
        ext_sni_add_clienthello,
        ext_sni_parse_serverhello,
        ext_sni_parse_clienthello,
        ext_sni_add_serverhello,
      },
      {
        TLSEXT_TYPE_extended_master_secret,
        NULL,
        ext_ems_add_clienthello,
        ext_ems_parse_serverhello,
        ext_ems_parse_clienthello,
        ext_ems_add_serverhello,
      },
      {
        TLSEXT_TYPE_renegotiate,
        NULL,
        ext_ri_add_clienthello,
        ext_ri_parse_serverhello,
        ext_ri_parse_clienthello,
        ext_ri_add_serverhello,
      },
      {
        TLSEXT_TYPE_supported_groups,
        NULL,
        ext_supported_groups_add_clienthello,
        ext_supported_groups_parse_serverhello,
        ext_supported_groups_parse_clienthello,
        dont_add_serverhello,
      },
      {
        TLSEXT_TYPE_ec_point_formats,
        NULL,
        ext_ec_point_add_clienthello,
        ext_ec_point_parse_serverhello,
        ext_ec_point_parse_clienthello,
        ext_ec_point_add_serverhello,
      },
      {
        TLSEXT_TYPE_session_ticket,
        NULL,
        ext_ticket_add_clienthello,
        ext_ticket_parse_serverhello,
        // Ticket extension client parsing is handled in ssl_session.c
        ignore_parse_clienthello,
        ext_ticket_add_serverhello,
      },
      {
        TLSEXT_TYPE_application_layer_protocol_negotiation,
        NULL,
        ext_alpn_add_clienthello,
        ext_alpn_parse_serverhello,
        // ALPN is negotiated late in |ssl_negotiate_alpn|.
        ignore_parse_clienthello,
        ext_alpn_add_serverhello,
      },
      {
        TLSEXT_TYPE_status_request,
        NULL,
        ext_ocsp_add_clienthello,
        ext_ocsp_parse_serverhello,
        ext_ocsp_parse_clienthello,
        ext_ocsp_add_serverhello,
      },
      {
        TLSEXT_TYPE_signature_algorithms,
        NULL,
        ext_sigalgs_add_clienthello,
        forbid_parse_serverhello,
        ext_sigalgs_parse_clienthello,
        dont_add_serverhello,
      },
      {
        TLSEXT_TYPE_next_proto_neg,
        NULL,
        ext_npn_add_clienthello,
        ext_npn_parse_serverhello,
        ext_npn_parse_clienthello,
        ext_npn_add_serverhello,
      },
      {
        TLSEXT_TYPE_certificate_timestamp,
        NULL,
        ext_sct_add_clienthello,
        ext_sct_parse_serverhello,
        ext_sct_parse_clienthello,
        ext_sct_add_serverhello,
      },
      {
        TLSEXT_TYPE_channel_id,
        ext_channel_id_init,
        ext_channel_id_add_clienthello,
        ext_channel_id_parse_serverhello,
        ext_channel_id_parse_clienthello,
        ext_channel_id_add_serverhello,
      },
      {
        TLSEXT_TYPE_srtp,
        ext_srtp_init,
        ext_srtp_add_clienthello,
        ext_srtp_parse_serverhello,
        ext_srtp_parse_clienthello,
        ext_srtp_add_serverhello,
      },
      {
        TLSEXT_TYPE_key_share,
        NULL,
        ext_key_share_add_clienthello,
        forbid_parse_serverhello,
        ignore_parse_clienthello,
        dont_add_serverhello,
      },
      {
        TLSEXT_TYPE_psk_key_exchange_modes,
        NULL,
        ext_psk_key_exchange_modes_add_clienthello,
        forbid_parse_serverhello,
        ext_psk_key_exchange_modes_parse_clienthello,
        dont_add_serverhello,
      },
      {
        TLSEXT_TYPE_early_data,
        NULL,
        ext_early_data_add_clienthello,
        ext_early_data_parse_serverhello,
        ext_early_data_parse_clienthello,
        ext_early_data_add_serverhello,
      },
      {
        TLSEXT_TYPE_supported_versions,
        NULL,
        ext_supported_versions_add_clienthello,
        forbid_parse_serverhello,
        ignore_parse_clienthello,
        dont_add_serverhello,
      },
      {
        TLSEXT_TYPE_cookie,
        NULL,
        ext_cookie_add_clienthello,
        forbid_parse_serverhello,
        ignore_parse_clienthello,
        dont_add_serverhello,
      },
      {
        TLSEXT_TYPE_quic_transport_parameters,
        NULL,
        ext_quic_transport_params_add_clienthello,
        ext_quic_transport_params_parse_serverhello,
        ext_quic_transport_params_parse_clienthello,
        ext_quic_transport_params_add_serverhello,
      },
      {
        TLSEXT_TYPE_token_binding,
        NULL,
        ext_token_binding_add_clienthello,
        ext_token_binding_parse_serverhello,
        ext_token_binding_parse_clienthello,
        ext_token_binding_add_serverhello,
      },
      {
        TLSEXT_TYPE_cert_compression,
        NULL,
        cert_compression_add_clienthello,
        cert_compression_parse_serverhello,
        cert_compression_parse_clienthello,
        cert_compression_add_serverhello,
      },
      {
        TLSEXT_TYPE_delegated_credential,
        NULL,
        ext_delegated_credential_add_clienthello,
        forbid_parse_serverhello,
        ext_delegated_credential_parse_clienthello,
        dont_add_serverhello,
      },
    };
    

    因爲我們要做的是SNI,所以看到了第一個ext,找到了它對應的add_clienthello是ext_sni_add_clienthello

  4. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    v2ray在wss協議下的代碼講解

    漏了剛才的代碼,補上

    conn, resp, err := dialer.Dial(uri, wsSettings.GetRequestHeader())
    return internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
    

    第一行代碼表示調用了開源的github.com/gorilla/websocket庫文件,不在此解讀了,你只要知道,通過這個開源庫,去建立了wss連接就好了,v2ray沒有自己實現wss,只是調用了第三方庫。

    第二行代碼,表示去建立了一個tcp連接,無它~

    希望我的講解,可以幫助大家少走很多彎路,看代碼知道哪些是v2ray實現的,哪些是第三方庫

    遇到問題,需要解決的時候,有一個思路,知道去看什麽代碼文件!

    比如爲什麽不像SS一樣需要自己指定加密算法呢?因爲這個是TLS自己協商出來的,而不是我們指定的,我們可以通過刪減剛才的config.CipherSuites來指定加密算法

    以及被中間人攻擊怎麽辦?我們可以通過config.Certificates 來設置自己的根證書解決

    爲什麽看不到AEAD加密算法實現呢?因爲在github.com/gorilla/websocket庫文件實現的數據AEAD加密

    等等問題,可以通過閲讀代碼自己回答。有需要,可以自己提issue。但是我都是自己改代碼,完成自我功能需求的客制化~

    有什麽v2ray的問題,可以給我留言。或者在v2ray的GitHub上提issue。

  5. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    火狐DoH和ESNI代碼講解

  6. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    火狐DoH和ESNI代碼講解

    @小二 #20

    你的這篇文章更側重向讀者解釋DNS的工作原理。以及如何DNS劫持,最後DoH如何解決了相關問題。還有哪些問題是遺留下來。很好的科普文章!

    但是我覺得這類科普類的文章太多了,不缺我一篇。我想寫自己的原創文章,國内講科普的代碼,講源碼的太少了。我希望把自己的代碼總結給大家,讓大家知道出了問題,去什麽目錄下找什麽文件,從什麽函數開始讀起,如何定位相關問題,並解決。

    如果我的原創文章足夠多,也足夠優秀,我覺得2049bbs的PageRank自然會提升~

  7. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    火狐DoH和ESNI代碼講解

    @electron8964 #16

    如果你看過我在品蔥的帖子,就知道我孩子都上大學了。。。

  8. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    火狐DoH和ESNI代碼講解

    @electron8964 #13 他寫小説挺好的,可惜共產黨封殺了他寫的小説。我不希望這些小説消失,便轉載到了品蔥,希望後人可以閲讀。

    我覺得,2000年左右,還可以讀到很多很多小説,後來就大肆封殺。我現在只能讀讀日本輕小説了。當年涼宮春日的小説挺火的

  9. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    火狐DoH和ESNI代碼講解

    @electron8964 #5 你也看慕容雪村的書麽?我有他親筆簽名~ 我在品蔥發了慕容雪村的小説。你可以去看看

  10. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    火狐DoH和ESNI代碼講解

    @小二 #2

    人話版本 :

    DNS協議的功能是通過域名查找對應的IP地址。DNS協議,明文跑在UDP協議下,端口寫死是53。

    因爲端口固定是53,所以特別好劫持。因爲是明文,所以GFW可以針對性劫持。

    攻擊方法:

    用戶瀏覽器發起DNS請求,比如www.google.com的ip是什麽?GFW全網抓包端口53的UDP流量

    捕獲了你的請求,然後僞造了一個假的DNS應答報文給你,IP當然是假的了。所以就上不了Google了。

    過去對品蔥就是這種封殺,僞造DNS。這個就是DNS劫持

    解決辦法:

    自己在本地的hosts裏增加正確的record就可以了。

    DNS over HTTPS

    就是把DNS請求通過https來發送,因爲https是加密的,所以克服了剛才的所有缺點。 DoH 有兩種方式,一種是發post請求,一種是發get請求。http的應答報文的body則是DNS的應答。

    通過調用DoHEncode把請求封裝成一個二進制的buffer請求。

    如果是post方式獲取DNS,則把剛才生成的buffer放到http的body裏,通過http二進制傳輸發送請求。

    如果是get方式獲取DNS,則把剛才的buffer通過base64編碼,放到http的查詢URI裏發送。

    得到的http應答報文根據DoHDecode函數,解析DNS應答,並返回給瀏覽器真實的ip地址。有效防止了DNS泄露,DNS劫持,等n多問題

    因爲大部分代碼都在拼http報文的head部分,就不去探究了。我們只用關心DOHEncode和DOHDecode兩個函數就好了。這兩個就是dns協議的拼裝和解析。其實也不用過度解讀。。。

  11. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    火狐DoH和ESNI代碼講解

    @Phragmites #8 蒹葭蒼蒼?看頭像猜的。 你好啊

  12. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    火狐DoH和ESNI代碼講解

    @梅菲斯特 #6 那是因爲我沒葱發文章,才發水樓。發一個35葱,都沒法回本。

  13. 霏艺Faye 图书管理员
    霏艺Faye   在小组 江湖 回复文章

    不知道是哪個管理員説我退葱了?

    莫名其妙説我是小號。有什麽懷疑就説出來,你覺得我是誰的小號!

  14. 霏艺Faye 图书管理员
    霏艺Faye   在小组 江湖 回复文章

    不知道是哪個管理員説我退葱了?

    @Ephemeris #4 看到了

    过阵子我会回品葱,继续主持我的广播站

    希望你能来看看

  15. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    火狐DoH和ESNI代碼講解

    SSLExp_EnableESNI

    tls13_ClientSetupESNI

    tls13_ServerDecryptEsniXtn

    再談下ESNI這個代碼,我不知道和TRR有什麽關聯,必須TRR打開,ESNI功能才能使用。感覺明明是獨立的兩個功能。

  16. 霏艺Faye 图书管理员
    霏艺Faye   在小组 2049BBS 回复文章

    火狐DoH和ESNI代碼講解

    GFW的問題,我這裏網絡不好,發文章比較卡。。

    通過TRR::OnDataAvailable函授收到應答報文,只看代碼On200Response,先不考慮異常情況

    DohDecode會解析應答報文,放到mDNS裏

    最後調用TRR::ReturnData 返回查詢結果,mHostResolver->CompleteLookup

    網絡不好,排版很累,沒法預覽。我不明白,這個地方爲什麽開啓了TRR才可以使用esni,不使用的話esni沒法啓用。爲什麽呢?