16:00:48 <Shelikhoo[mds]> #startmeeting tor anti-censorship meeting
16:00:48 <MeetBot> Meeting started Thu Feb  5 16:00:48 2026 UTC.  The chair is Shelikhoo[mds]. Information about MeetBot at https://wiki.debian.org/MeetBot.
16:00:48 <MeetBot> Useful Commands: #action #agreed #help #info #idea #link #topic.
16:00:48 <Shelikhoo[mds]> here is our meeting pad: https://pad.riseup.net/p/r.9574e996bb9c0266213d38b91b56c469
16:00:48 <Shelikhoo[mds]> editable link available on request
16:00:57 <meskio[mds]> :)
16:00:59 <gaba> hi
16:02:07 <cohosh> hi
16:03:03 <Shelikhoo[mds]> I didn’t see any new discussion topics
16:03:45 <ggus> o/
16:04:33 <Shelikhoo[mds]> Hi gus, do you wants to suggest a discussion point
16:04:34 <Shelikhoo[mds]> Or just saying hi
16:04:47 <meskio[mds]> I just added one
16:04:51 <ggus> i'm planning to send call for snowlfka proxies to tor-relays today, any thoughts/ideas/suggestions? https://pad.riseup.net/p/4dOwW-5eaAkMfFFoHlEM-snowflake-call-keep
16:04:51 <meskio[mds]> can we remove the old ones?
16:05:44 <Shelikhoo[mds]> I think we can remove the old ones, but there is a new topic about allow listing restrictions in Russia
16:06:13 <Shelikhoo[mds]> Let’s proceed with gus’s discussion point first
16:07:07 <meskio[mds]> ggus: nice, it looks good to me
16:07:42 <cohosh> it looks great. i do think we should list the options in order of positive user experience (maybe 1. orbot, 2. webext, 3. standalone, 4. badge)?
16:08:00 <Shelikhoo[mds]> I wonder if we can make the link about running a browser extension navigate to the corresponding section
16:08:11 <Shelikhoo[mds]> It might be possible with a # tag
16:08:50 <Shelikhoo[mds]> - Option 2: Install Snowflake browser extension:
16:08:50 <Shelikhoo[mds]> https://snowflake.torproject.org/
16:09:06 <ggus> like this_ https://snowflake.torproject.org/#03-donate-bandwidth
16:09:16 <Shelikhoo[mds]> Yes…
16:09:46 <Shelikhoo[mds]> Thanks… that is end of my suggestion
16:10:26 <cohosh> thanks for doing this ggus
16:10:42 <Shelikhoo[mds]> Yes! Thanks ggus!
16:10:45 <cohosh> i didn't realize how overloaded we were until seeing the shared user reports with rendezvous failures in the logs
16:11:16 <meskio[mds]> yes, it looks like it takes many retries to connect to snowflake, and some times it doesn't work
16:11:21 <cohosh> our prometheus metrics show clients being denied for lack of proxies, but it's hard to tell how that impacts user experience directly
16:12:43 <meskio[mds]> the thing with snowflake is that we tend to have most proxies iddle, until something happens and the network gets overloaded
16:13:15 <ggus> if you open the snowflake badge page now, you will get users immediately
16:13:29 <meskio[mds]> we could reconsider the webextensions allowing for more than one client, or having the broker telling the proxies how often to poll
16:14:57 <cohosh> i think the default is already that webextensions with less restrictive NATs allow 2 clients to connect
16:15:08 <cohosh> let me quickly check
16:15:24 <meskio[mds]> ahh, nice, I didn't know
16:16:15 <cohosh> https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake-webext/-/blob/9ed59f79bdfacee7c72d0ddca8987bb52c644c38/snowflake.js#L113
16:17:00 <cohosh> ggus: good point about the badge, maybe it's also a good option to add more temporary churn to the pool
16:17:01 <meskio[mds]> should we do this also for restricted? grafana claims that we have many unrestricted clients in Iran...
16:17:08 * ggus sending the email
16:17:55 <cohosh> meskio[mds]: we could, i'm not seeing any clients with unrestricted NATs denied at the broker
16:18:26 <cohosh> we still have a lot of idle proxies in that pool
16:18:58 <meskio[mds]> mmm, true
16:19:08 <meskio[mds]> maybe not worth it
16:20:11 <Shelikhoo[mds]> Yeah, anything more we would like to discuss about this topic?
16:20:37 <meskio[mds]> I don't think so
16:20:57 <meskio[mds]> thanks ggus for making a call
16:21:09 <Shelikhoo[mds]> thanks ggus
16:21:13 <Shelikhoo[mds]> the next topic is about
16:21:14 <Shelikhoo[mds]> whitelisting in russia
16:21:15 <Shelikhoo[mds]> https://gitlab.torproject.org/tpo/anti-censorship/censorship-analysis/-/issues/40071
16:21:26 <meskio[mds]> I added that one
16:22:05 <Shelikhoo[mds]> I did see the part that only some messager is working when the allowlisting is enforced
16:22:09 <meskio[mds]> it looks like is becoming more common that for some periods of time users in some networks in russia can only access a short list of in-country allowlist services
16:22:39 <Shelikhoo[mds]> Does this means the cross border dns also get blocked
16:22:40 <meskio[mds]> I was brainstorming myself a bit on this issue on how to make Tor work for those users
16:22:51 <Shelikhoo[mds]> or we still don't know for sure
16:23:02 <meskio[mds]> yes, it could be that dnstt/splitstream work
16:23:27 <meskio[mds]> maybe something to test now that orbot is including dnstt...
16:23:53 <meskio[mds]> I mean, asking users to try out
16:24:05 <Shelikhoo[mds]> yes... I was thinking if the effort around dns tunnel thing can be shared
16:24:29 <meskio[mds]> I was considering if we should look into PTs of proxing the traffic over messengeres, to use those services that are available
16:24:45 <meskio[mds]> there are a bunch of literature on how to offuscate traffic in text
16:25:06 <meskio[mds]> and some code around, but I assume is a big project
16:25:39 <Shelikhoo[mds]> the other issue is that it is not hard to russian messager app to block our account
16:26:13 <meskio[mds]> yes, true, we end up distributing accounts like we distribute bridges, but been probably harder to create them
16:26:20 <cohosh> is cdn77 one of the allowlisted providers?
16:26:37 <cohosh> or any of the fronts we've used for them, I guess?
16:26:40 <meskio[mds]> no
16:26:41 <meskio[mds]> only russian services
16:26:59 <ggus> nina13[mds]: ping
16:27:03 <meskio[mds]> AFAIK no full providers, no in-country traffic, just specific services
16:27:26 <meskio[mds]> but it looks like is SNI based and not so much IP based...
16:27:29 <Shelikhoo[mds]> I think we should try the dns tunnel thing, if the speed is insufficient, we can attempt ip level source forging
16:27:39 <meskio[mds]> I think some people are just using webtunnel with the right SNI
16:28:05 <Shelikhoo[mds]> and for SNI based censorship, there are many options to deal with that without too much effort like sni imitation
16:28:06 <meskio[mds]> sounds good, to me, and that will also be useful for the situation in Iran
16:28:42 <Shelikhoo[mds]> I think at some point we should also have some try about ip level source forging
16:28:55 <nina13[mds]> ggus: I'm here
16:29:09 <dcf1> fyi a plaintext udp/53 DNS tunnel is an "arms race" style transport: it is easy to detect and block once the censor knows what to look for
16:29:09 <Shelikhoo[mds]> it will be able to deal with ip level censorship
16:29:26 <meskio[mds]> nina13: just discussing your issue about russian whitelisting
16:29:30 <dcf1> I think of it as a last-resort "emergency use only" transport because it's security through obscurity
16:30:27 <meskio[mds]> dcf1: I agree, it looks like it was very useful during the Iranian blackout, but let's not use it more than just in extreme situations
16:31:13 <meskio[mds]> BTW, champa is another tool that is often useful in Iran with nothing else works, because they tend to allowlist google first
16:31:55 <meskio[mds]> we were discussing if champa will be faster than dnstt, and nicer user experience with all the Tor overhead
16:32:06 <dcf1> Yes, and that one is not security by obscurity because the true destination is actually encrypted, unlike a plaintext DNS tunnel
16:32:34 <Shelikhoo[mds]> I think amp cache also have some kind of throttling
16:32:35 <dcf1> champa would be faster than dnstt, except for rate limiting at the AMP cache
16:32:49 <dcf1> I don't know a solution to that. It's a bummer.
16:33:04 <meskio[mds]> the rate limit is per account?
16:33:16 <dcf1> Try it, it works at 10 KB/s for a few minutes, then stops working completely for a few hours.
16:33:29 <dcf1> Miserable usability.
16:33:34 <meskio[mds]> wow, ok
16:33:45 <meskio[mds]> a pity
16:34:07 <Shelikhoo[mds]> is this a limit based on the html page loaded
16:34:15 <Shelikhoo[mds]> or something else
16:34:27 <dcf1> I think it is keyed on the client and not the server, not 100% sure
16:34:28 <Shelikhoo[mds]> let's say if we request images or other resources
16:34:47 <dcf1> images are problematic because the AMP cache may transcode them
16:35:32 <dcf1> https://developers.google.com/amp/cache/overview#cache-optimizations-and-modifications
16:35:40 <dcf1> "Conversion of images to smaller and mobile-friendlier image formats, such as converting GIF, PNG, and JPEG format images to WebP in browsers that support WebP." etc.
16:36:26 <dcf1> There may be a more efficient encoding than the current base64-in-HTML, but it's not obvious
16:37:18 <Shelikhoo[mds]> I see web font can also be shipped
16:37:49 <Shelikhoo[mds]> I image it is a more complex format and won't be transformed at edge as easy as images
16:38:01 <dcf1> feel free to experiment, I don't see how it helps against rate limiting though
16:38:06 <Shelikhoo[mds]> I imagine it is a more complex format and won't be transformed at edge as easy as images
16:38:10 <Shelikhoo[mds]> yes....
16:39:06 <Shelikhoo[mds]> the other option is to use ip source forging
16:39:41 <Shelikhoo[mds]> I think this is something that would be hard for censor to filter even with the knowledge we are doing so
16:39:48 <cohosh> don't most ISPs use ingress/egress filtering to prevent that?
16:41:29 <Shelikhoo[mds]> it is possible for martian packet to be filtered
16:42:30 <Shelikhoo[mds]> however, when it comes to internet traffic exchange, unless an ip address is announced by a particular ISP, it will not be able to drop packet "from" it
16:43:32 <Shelikhoo[mds]> to send a packet with forged source, one requires an isp that don't filter outgoing traffics
16:43:59 <Shelikhoo[mds]> which is not common for most residential or big data center
16:44:14 <Shelikhoo[mds]> however, it is still possible
16:45:01 <Shelikhoo[mds]> so, so long as the destination address is announced, we can send a packet to it and claim the packet is from any source
16:45:21 <Shelikhoo[mds]> so long as the source is not directly adjacent the the destination
16:46:16 <Shelikhoo[mds]> EOF
16:46:49 <Shelikhoo[mds]> we still have a paper to discuss
16:47:03 <meskio[mds]> yes, I'm done with this topic, we can move to the reading group
16:47:06 <Shelikhoo[mds]> I see there is an interesting link: https://gitlab.torproject.org/tpo/anti-censorship/censorship-analysis/-/issues/40068#note_3333227
16:47:27 <Shelikhoo[mds]> okay let's move to the reading group
16:47:38 <Shelikhoo[mds]> We will discuss "Fingerprint-resistant DTLS for usage in Snowflake" on Feb 5
16:47:38 <Shelikhoo[mds]> https://www.petsymposium.org/foci/2025/foci-2025-0006.php
16:47:48 <Shelikhoo[mds]> https://www.petsymposium.org/foci/2025/foci-2025-0006.php
16:48:50 <Shelikhoo[mds]> The download link for the paper is available from the link above
16:50:08 <Shelikhoo[mds]> the super quick summary from me is that the dtls used in webrtc stack(which we are using in snowflake) can be fingerprinted in the same way as tls
16:50:45 <Shelikhoo[mds]> and this paper presented the utls equivalent for dtls
16:51:23 <meskio[mds]> it is a nice paper, even though we have discussed this topic for years I learn many new things
16:51:25 <cohosh> this is really nice work, great job theodorsm!
16:51:35 <theodorsm> tnx!
16:51:48 <Shelikhoo[mds]> yes, thanks theodorsm
16:51:55 <theodorsm> worth noting that both chrome and firefox uses dtls 1.3 by default now in webrtc
16:52:25 <cohosh> thanks for tracking down those setup:pass and setup:active attributes
16:52:29 <meskio[mds]> interesting, do they use ECH?
16:52:34 <Shelikhoo[mds]> yes... I think we might wants to consider maybe find a way to use dtls 1.3 as well
16:52:58 <cohosh> i took a look at the RFC and it makes sense from a latency perspective for the proxy to be the DTLS client: https://datatracker.ietf.org/doc/html/rfc5763
16:53:11 <meskio[mds]> pion is in progress to support it: https://github.com/pion/dtls/issues/727
16:53:12 <theodorsm> I am working on implementing dtls 1.3 for pion currently. Got funding through nlnet to do it.
16:53:28 <meskio[mds]> nice
16:53:29 <cohosh> amazing, congrats on the funding!
16:53:50 <theodorsm> thanks:)
16:54:18 <theodorsm> One thing we couldn't really figure out is why a lot of handshakes fail. see Table 1.
16:54:21 <Shelikhoo[mds]> nice!!!
16:54:53 <theodorsm> even the baseline had around 12% failed handshakes. (calcualted from the traffic capture)
16:55:10 <theodorsm> the baseline is a non-modified snowflake standalone proxy
16:55:10 <cohosh> that surprised me
16:56:02 <theodorsm> Maybe it was retried later, but I have no stats on that and all the captures are deleted now
16:56:34 <meskio[mds]> and the webextension was failing even more
16:56:42 <cohosh> it sounds like a good idea to follow up on that
16:56:47 <Shelikhoo[mds]> I think this is related to the other side of the connection
16:57:04 <Shelikhoo[mds]> if we are running on a public pool
16:57:43 <meskio[mds]> maybe this is something to add to our list of research ideas: https://gitlab.torproject.org/tpo/anti-censorship/team/-/wikis/Research-ideas
16:57:50 <cohosh> Shelikhoo[mds]: that's true, we've heard from proxy operators about clients connecting and terminating the connection in what looks like an automated way
16:58:26 <theodorsm> I saw a few weird scanners from a datacenter in the NL
16:58:28 <cohosh> so it could be weirdly behaving clients
16:58:48 <theodorsm> But I filtered them out from calc the failure rate
16:59:07 <theodorsm> Also, do we have metrics on which types of proxies are actually
16:59:10 <theodorsm> being matched and successfully used by clients.
16:59:24 <cohosh> theodorsm: oh yeah that was a point i wanted to discuss
16:59:57 <cohosh> our broker metrics collect just poll data, and our bridge metrics collect just client data
17:00:02 <Shelikhoo[mds]> yeah, I think we can try to see the client/server hello from the peer and attempt to guess why the handshake fails
17:00:10 <cohosh> we don't have metrics about proxies that actually connect to the bridge
17:00:24 <cohosh> it's tricky for us to do this but probably not impossible
17:00:56 <cohosh> i was thinking a little about this in the context of limiting malicious proxy polls as well
17:01:25 <cohosh> we could have the bridge give proxies some kind of signed receipt when they tunnel data from a client: if a client successfully connects, the bridge would send an authenticated receipt to the proxy, which would then hand that receipt to the broker
17:01:36 <cohosh> it's possible that a malicious proxy could serve a client honestly every once in a while to get these receipts, but maybe it would at least function as some level of network-based proof of work?
17:02:28 <Shelikhoo[mds]> (the meeting time is almost over. we can keep the meeting open a little longer. feel free to leave if you have conflicting schedules)
17:02:48 <cohosh> it would take some engineering network that might not be worth it for metrics, but if it also has this DoS defence benefit then it could be interesting to consider
17:02:50 <meskio[mds]> (I can stay for a while)
17:03:33 <Shelikhoo[mds]> I think we can at least let the proxy send its own identity "token" to both server and broker
17:04:00 <theodorsm> cohosh: would be cool to brainstorm a bit more on. Do you have an issue for it somewhere?
17:04:03 <Shelikhoo[mds]> so that we can track if an instance is working correctly
17:04:25 <cohosh> Shelikhoo[mds]: that's another way to do it: have the bridge report extra stats about connected proxies
17:05:02 <cohosh> theodorsm: i'll make one after this discussion and mention you in it
17:05:04 <Shelikhoo[mds]> yes, I feel the signed receipt thing would require some extra work on the proxy side
17:05:26 <cohosh> we'd have to extend the protocol for that bridge-proxy connection
17:05:29 <Shelikhoo[mds]> which is more "expensive" for us, since we need to do it twice
17:06:00 <cohosh> it's also the flip side of https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/issues/31804
17:06:24 <Shelikhoo[mds]> I think my udp transport mode already support sending extra options from proxy to server via websocket url
17:06:28 <cohosh> which would try to prevent proxy connections to a bridge without a verified client match from the broker
17:06:56 <Shelikhoo[mds]> so if we just let the server to report the proxy stat
17:06:58 <cohosh> Shelikhoo[mds]: oh i see you mean, we'd have to implement it in the web code and the go library code
17:09:04 <Shelikhoo[mds]> rather than let the proxy receive extra data from server
17:09:24 <Shelikhoo[mds]> this is because the server can not verify the client connection is valid
17:09:40 <Shelikhoo[mds]> when the websocket connection is created
17:09:50 <Shelikhoo[mds]> as it has not received any data from client at that point
17:10:14 <Shelikhoo[mds]> it will need to at least wait for some traffic on kcp level
17:10:50 <Shelikhoo[mds]> which would pass the point when the server can send info to proxy over http protocol
17:11:00 <Shelikhoo[mds]> and it will have to send some websocket message
17:11:25 <cohosh> yeah that would be difficult to do
17:11:43 <cohosh> and it's what we would want for this DoS prevention feature
17:11:44 <Shelikhoo[mds]> so I think it is better for the proxy to just generate an random id
17:11:59 <Shelikhoo[mds]> and send it to both broker and server
17:12:20 <Shelikhoo[mds]> and let the broker and server do the check on their side
17:12:21 <cohosh> i guess the bridge and broker could communicate directly to compare proxy ids
17:12:58 <Shelikhoo[mds]> yes..
17:14:53 <Shelikhoo[mds]> maybe we can continue the discussion in an issue
17:15:12 <cohosh> either way this is a pretty big project, and won't happen soon, i'll make an issue to summarize the discussion and think about whether to pursue it
17:15:13 <Shelikhoo[mds]> since I think this will take a while to be done
17:15:27 <Shelikhoo[mds]> thanks cohosh!
17:15:42 <theodorsm> thanks!
17:15:57 <Shelikhoo[mds]> there is another good thing about the proxy sending its instance id
17:16:33 <Shelikhoo[mds]> this would allow the broker to send different "next poll at" to different proxies running on the same ip
17:17:01 <Shelikhoo[mds]> to avoid sending the same "next poll at" to all the proxies running on the same ip address
17:17:13 <Shelikhoo[mds]> and allow then to gracefully share the quota
17:17:26 <Shelikhoo[mds]> eof from me on this topic
17:17:54 <meskio[mds]> one thing interesting from the paper for me is that chrome randomizes its fingerprints, I guess this will make it hard for censors to make an allowlist of DTLS fingerprints
17:18:51 <meskio[mds]> the one I was wondering if could be exploided by censors is the fact that WebRTC connections are always started by the proxy, I wonder what will be the collateral damage if censors block all WebRTC ClientHello arriving from outside the country
17:19:42 <meskio[mds]> wouldn't normal clients retry and use a different client starting? I have no idea what is a normal behaviour
17:20:06 <Shelikhoo[mds]> I think webrtc determine who is the "dtls client" in a "magic" way... so it is hard to say who will be the "dtls client"
17:20:19 <theodorsm> ohh interesting attack vector. But we could also change up who is sending the SDP offer no?
17:21:08 <theodorsm> According to RFC 5763, the SDP offer must include the\nsetup:actpass attribute, and it is recommended that the SDP answer\nuses the setup:active attribute [31]. The peer designated as active is\nresponsible for initiating the DTLS handshake by sending the CH.\nSince the Snowflake client is implemented to always send the SDP\noffer, the proxy—in responding with the SDP answer—becomes\nthe
17:21:14 <theodorsm> active peer and thus initiates the handshake.
17:21:53 <cohosh> the reason we have the client do the offer in snowflake is to make it so the client only has to do 1 round trip with the broker
17:22:12 <cohosh> since that connection is less reliable and more costly to us than proxy connections to the broker
17:22:56 <Shelikhoo[mds]> (shell withdraw the magic line above... it is just me don't understand the understand logic behind it)
17:24:07 <theodorsm> you're not the only one, took me a while to understand too
17:24:10 <Shelikhoo[mds]> I think this is unlikely to be censor's next move... but we might wants to consider this next time snowflake get blocked
17:24:28 <cohosh> theodorsm: yeah i appreciated that detail in the paper, thanks for noting it!
17:24:50 <meskio[mds]> I agree, I don't think we need to react on this, I just wanted to point it out to keep it in mind
17:25:39 <meskio[mds]> I think we covered all the points I wanted to bring on this reading group, I'm done :)
17:26:39 <cohosh> yeah it was a good discussion, thanks :)
17:26:42 <Shelikhoo[mds]> eof from me as well
17:26:52 <Shelikhoo[mds]> anything else we wants to discuss in this meeting
17:26:52 <theodorsm> \0 EOF
17:26:55 <Shelikhoo[mds]> (we are overtime)
17:27:07 <Shelikhoo[mds]> #endmeeting