[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-73227":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":19,"compositeScore":20,"rankGlobal":10,"rankLanguage":10,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":22,"hasPages":22,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":31,"readmeContent":32,"aiSummary":33,"trendingCount":16,"starSnapshotCount":16,"syncStatus":17,"lastSyncTime":34,"discoverSource":35},73227,"httptap","monasticacademy\u002Fhttptap","monasticacademy","View HTTP\u002FHTTPS requests made by any Linux program","https:\u002F\u002Fwww.monasticacademy.org",null,"Go",4166,65,10,12,0,2,9,6,63.36,"MIT License",false,"main",[25,26,27,28,29,30],"gvisor","linux-network-namespace","man-in-the-middle","monastery","networking","tun-device","2026-06-12 04:01:08","\u003Ch1 align=\"center\">\n  \u003Cimg src=\".\u002Fdocs\u002Freadme-header.webp\" alt=\"Monastic Academy\" height=\"450px\">\n  \u003Cbr>\n  httptap\n  \u003C\u002Fbr>\n\u003C\u002Fh1>\n\u003Cp align=\"center\">\n  \u003Ca href=\"https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fmonasticacademy\u002Fhttptap\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fgo.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square\" alt=\"Documentation\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmonasticacademy\u002Fhttptap\u002Factions\">\u003Cimg src=\"https:\u002F\u002Fgithub.com\u002Fmonasticacademy\u002Fhttptap\u002Fworkflows\u002FTest\u002Fbadge.svg\" alt=\"Build Status\">\u003C\u002Fa>\n\u003C\u002Fp>\n\u003Cbr>\n\nView the HTTP and HTTPS requests made by any linux program by running `httptap -- \u003Ccommand>`. For example, the following runs curl on \"monasticacademy.org\", which results in an HTTP status of 308 (Redirect):\n\n```shell\n$ httptap -- curl https:\u002F\u002Fmonasticacademy.org\n---> GET https:\u002F\u002Fmonasticacademy.org\u002F\n\u003C--- 308 https:\u002F\u002Fmonasticacademy.org\u002F (15 bytes)\n```\n\nNow let's try the same thing with an HTTP request from python. This time we see that python follows the redirect and gets a 200 OK response:\n\n```shell\nhttptap -- python -c \"import requests; requests.get('https:\u002F\u002Fmonasticacademy.org')\"\n---> GET https:\u002F\u002Fmonasticacademy.org\u002F\n\u003C--- 308 https:\u002F\u002Fmonasticacademy.org\u002F (15 bytes)\n---> GET https:\u002F\u002Fwww.monasticacademy.org\u002F\n\u003C--- 200 https:\u002F\u002Fwww.monasticacademy.org\u002F (5796 bytes)\n```\n\nTo run `httptap` you do not need to be the root user. You do not need to set up any kind of daemon or make any system-wide changes to your system (edit: on Ubuntu 23.10 and later you will need to run [the sysctl documented below](#ubuntu-2310-and-later)). It will not create any iptables rules or change your routing table, and generally will not affect any other processes running on the same system. The `httptap` executable is a static Go binary that runs without dependencies.\n\nHttptap only runs on linux at present. It makes use of linux-specific system calls -- in particular network namespaces -- that will unfortunately make it very difficult to port to other operating systems. If you know how httptap could be ported to other operating systems then please get in touch!\n\n# Install pre-built binary\n\n```shell\ncurl -L https:\u002F\u002Fgithub.com\u002Fmonasticacademy\u002Fhttptap\u002Freleases\u002Flatest\u002Fdownload\u002Fhttptap_linux_$(uname -m).tar.gz | tar xzf -\n```\n\nFor all versions and CPU architectures see the [latest releases page](https:\u002F\u002Fgithub.com\u002Fmonasticacademy\u002Fhttptap\u002Freleases\u002Flatest).\n\n# Install with Go\n\n```shell\ngo install github.com\u002Fmonasticacademy\u002Fhttptap@latest\n```\n\n# Ubuntu 23.10 and later\n\nOn Ubuntu 23.10 and later you will need to run the following in order to use httptap:\n\n```shell\nsudo sysctl -w kernel.apparmor_restrict_unprivileged_unconfined=0\nsudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0\n```\n\nWhat this does is disable a [recent kernel feature that restricts unprivileged user namespaces](https:\u002F\u002Fubuntu.com\u002Fblog\u002Fubuntu-23-10-restricted-unprivileged-user-namespaces). The above may also be needed on other distros that have disabled unprivileged user namespaces by default. I will update this documentation as I learn more. I am investigating ways to avoid the need for this entirely by shipping an apparmor profile with httptap.\n\n# Quickstart\n\nLet's run a simple test:\n\n```shell\nhttptap -- curl -s https:\u002F\u002Fbuddhismforai.sutra.co -o \u002Fdev\u002Fnull\n---> GET https:\u002F\u002Fbuddhismforai.sutra.co\u002F\n\u003C--- 302 https:\u002F\u002Fbuddhismforai.sutra.co\u002F (117 bytes)\n```\n\nWhat happened here is that we ran `curl -s https:\u002F\u002Fbuddhismforai.sutra.co -o \u002Fdev\u002Fnull` and it received a 302 redirect from the server. `httptap` printed summaries of the HTTP requests and their responses. Let's see how it changes if we tell curl to follow redirects by adding `-L`:\n\n```shell\nhttptap -- curl -sL https:\u002F\u002Fbuddhismforai.sutra.co -o \u002Fdev\u002Fnull\n---> GET https:\u002F\u002Fbuddhismforai.sutra.co\u002F\n\u003C--- 302 https:\u002F\u002Fbuddhismforai.sutra.co\u002F (117 bytes)\n---> GET https:\u002F\u002Fbuddhismforai.sutra.co\u002Fspace\u002Fcbodvy\u002Fcontent\n\u003C--- 200 https:\u002F\u002Fbuddhismforai.sutra.co\u002Fspace\u002Fcbodvy\u002Fcontent (6377 bytes)\n```\n\nNow we can see that after receiving the 302 redirect, curl made an additional HTTP request to the URL to which it was redirected, which is what you expect when using `-L` with curl.\n\nLet's see what HTTP endpoints the Google Cloud command line interface uses to list compute resources (this requires that you have gcloud installed and are signed in):\n\n```shell\n$ httptap -- gcloud compute instances list\n---> POST https:\u002F\u002Foauth2.googleapis.com\u002Ftoken\n\u003C--- 200 https:\u002F\u002Foauth2.googleapis.com\u002Ftoken (997 bytes)\n---> GET https:\u002F\u002Fcompute.googleapis.com\u002Fcompute\u002Fv1\u002Fprojects\u002Fmaple-public-website\u002Faggregated\u002Finstances?alt=json&includeAllScopes=True&maxResults=500&returnPartialSuccess=True\n\u003C--- 200 https:\u002F\u002Fcompute.googleapis.com\u002Fcompute\u002Fv1\u002Fprojects\u002Fmaple-public-website\u002Faggregated\u002Finstances?alt=json&includeAllScopes=True&maxResults=500&returnPartialSuccess=True (19921 bytes)\nNAME       ZONE        MACHINE_TYPE  PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP     STATUS\n\u003Cyour cloud instances listed here>\n```\n\nWhat happened here is that we ran `gcloud compute instances list`, which lists the compute instances that the signed-in user has on Google Cloud. The bottom two lines of output were printed by `gcloud`; the rest were printed by `httptap` and show what HTTP requests `gcloud` used to get the information it printed.\n\nLet's see what HTTP endpoints kubectl uses in a \"get all\" (this requires that you have kubectl installed and are authenticated to a cluster):\n\n```shell\n$ httptap --https 443 6443 -- kubectl get all --insecure-skip-tls-verify\n---> GET https:\u002F\u002Fcluster:6443\u002Fapi\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fpods?limit=500\n\u003C--- 200 https:\u002F\u002Fcluster:6443\u002Fapi\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fpods?limit=500 (38345 bytes)\n---> GET https:\u002F\u002Fcluster:6443\u002Fapi\u002Fv1\u002Fnamespaces\u002Fdefault\u002Freplicationcontrollers?limit=500\n\u003C--- 200 https:\u002F\u002Fcluster:6443\u002Fapi\u002Fv1\u002Fnamespaces\u002Fdefault\u002Freplicationcontrollers?limit=500 (2509 bytes)\n---> GET https:\u002F\u002Fcluster:6443\u002Fapi\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fservices?limit=500\n\u003C--- 200 https:\u002F\u002Fcluster:6443\u002Fapi\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fservices?limit=500 (5586 bytes)\n---> GET https:\u002F\u002Fcluster:6443\u002Fapis\u002Fapps\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fdaemonsets?limit=500\n\u003C--- 200 https:\u002F\u002Fcluster:6443\u002Fapis\u002Fapps\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fdaemonsets?limit=500 (3052 bytes)\n---> GET https:\u002F\u002Fcluster:6443\u002Fapis\u002Fapps\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fdeployments?limit=500\n\u003C--- 200 https:\u002F\u002Fcluster:6443\u002Fapis\u002Fapps\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fdeployments?limit=500 (7438 bytes)\n---> GET https:\u002F\u002Fcluster:6443\u002Fapis\u002Fapps\u002Fv1\u002Fnamespaces\u002Fdefault\u002Freplicasets?limit=500\n\u003C--- 200 https:\u002F\u002Fcluster:6443\u002Fapis\u002Fapps\u002Fv1\u002Fnamespaces\u002Fdefault\u002Freplicasets?limit=500 (47211 bytes)\n---> GET https:\u002F\u002Fcluster:6443\u002Fapis\u002Fapps\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fstatefulsets?limit=500\n\u003C--- 200 https:\u002F\u002Fcluster:6443\u002Fapis\u002Fapps\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fstatefulsets?limit=500 (1416 bytes)\n---> GET https:\u002F\u002Fcluster:6443\u002Fapis\u002Fautoscaling\u002Fv2\u002Fnamespaces\u002Fdefault\u002Fhorizontalpodautoscalers?limit=500\n\u003C--- 200 https:\u002F\u002Fcluster:6443\u002Fapis\u002Fautoscaling\u002Fv2\u002Fnamespaces\u002Fdefault\u002Fhorizontalpodautoscalers?limit=500 (2668 bytes)\n---> GET https:\u002F\u002Fcluster:6443\u002Fapis\u002Fbatch\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fcronjobs?limit=500\n\u003C--- 200 https:\u002F\u002Fcluster:6443\u002Fapis\u002Fbatch\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fcronjobs?limit=500 (3134 bytes)\n---> GET https:\u002F\u002Fcluster:6443\u002Fapis\u002Fbatch\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fjobs?limit=500\n\u003C--- 200 https:\u002F\u002Fcluster:6443\u002Fapis\u002Fbatch\u002Fv1\u002Fnamespaces\u002Fdefault\u002Fjobs?limit=500 (2052 bytes)\n\u003Cordinary kubectl output here>\n```\n\nIn the above, `--insecure-skip-tls-verify` is necessary because kubectl doesn't use the httptap-generated certificate authority, and `--https 443 6443` says to treat TCP connections on ports 443 and 6443 as HTTPS connections, which is needed because my cluster's API endpoint uses port 6443.\n\nLet's see how DNS-over-HTTP works when you use `--doh-url` with curl:\n\n```shell\n$ httptap -- curl -sL --doh-url https:\u002F\u002Fcloudflare-dns.com\u002Fdns-query https:\u002F\u002Fbuddhismforai.sutra.co -o \u002Fdev\u002Fnull\n---> POST https:\u002F\u002Fcloudflare-dns.com\u002Fdns-query\n\u003C--- 200 https:\u002F\u002Fcloudflare-dns.com\u002Fdns-query (149 bytes)\n---> POST https:\u002F\u002Fcloudflare-dns.com\u002Fdns-query\n\u003C--- 200 https:\u002F\u002Fcloudflare-dns.com\u002Fdns-query (150 bytes)\n---> GET https:\u002F\u002Fbuddhismforai.sutra.co\u002F\n\u003C--- 302 https:\u002F\u002Fbuddhismforai.sutra.co\u002F (117 bytes)\n---> GET https:\u002F\u002Fbuddhismforai.sutra.co\u002Fspace\u002Fcbodvy\u002Fcontent\n\u003C--- 200 https:\u002F\u002Fbuddhismforai.sutra.co\u002Fspace\u002Fcbodvy\u002Fcontent (6377 bytes)\n```\n\nWhat happened here is that we told `curl` to request the url \"https:\u002F\u002Fbuddhismforai.sutra.co\", using the cloudflare DNS-over-HTTP service at `cloudflare-dns.com`. In the output we see that `curl` made 4 HTTP requests in total; the first two were DNS lookups, and then the second two were the ordinary HTTP requests for buddhismforai.sutra.co.\n\nLet's print the contents of the DNS-over-HTTP payloads:\n\n```shell\n$ httptap --head --body -- curl -sL --doh-url https:\u002F\u002Fcloudflare-dns.com\u002Fdns-query https:\u002F\u002Fbuddhismforai.sutra.co -o \u002Fdev\u002Fnull\n---> POST https:\u002F\u002Fcloudflare-dns.com\u002Fdns-query\n> Accept: *\u002F*\n> Content-Type: application\u002Fdns-message\n> Content-Length: 40\nbuddhismforaisutraco\n\u003C--- 200 https:\u002F\u002Fcloudflare-dns.com\u002Fdns-query (149 bytes)\n\u003C Alt-Svc: h3=\":443\"; ma=86400\n\u003C Server: cloudflare\n\u003C Date: Tue, 24 Dec 2024 18:13:12 GMT\n\u003C Content-Type: application\u002Fdns-message\n\u003C Access-Control-Allow-Origin: *\n\u003C Content-Length: 149\n\u003C Cf-Ray: 8f7290631e334211-EWR\nbuddhismforaisutraco�\n��w�4+#G�.           \u003Cwildcardsutraco\therokudnscom�4+!�=�4+\n...\n```\n\nHere the `--head` option tells httptap to print the HTTP headers, and `--body` tells it to print the raw HTTP payloads. To keep it short I'm showing just the first request\u002Fresponse pair.\n\n# HAR output\n\nYou can dump the HTTP requests and responses to a HAR file like this:\n\n```\n$ httptap --dump-har out.har -- curl -Lso \u002Fdev\u002Fnull https:\u002F\u002Fmonasticacademy.org\n```\n\nThere are many HAR viewers out there that can visualize this dump file. For example here is how the above looks in the [Google HAR Analyzer](https:\u002F\u002Ftoolbox.googleapps.com\u002Fapps\u002Fhar_analyzer\u002F):\n\n![HAR Analyzer Screenshot](docs\u002Fhar-screenshot.png)\n\nAgain, what you're looking at here is one HTTP request to https:\u002F\u002Fmonasticacademy.org that returns a 308 Redirect, followed by a second HTTP request to https:\u002F\u002Fwww.monasticacademy.org that returns a 200 OK.\n\n# Reaching localhost\n\nTo reach a localhost port, replace \"localhost\" with \"host.httptap.local\" or the special IP address 169.254.77.65. Traffic to these destinations will be routed to localhost on your machine.\n\nThe situation here is that in linux every network namespace automatically gets its own loopback device (127.0.0.1), and these can't be shared. This means that if a process running within httptap tries to connect to 127.0.0.1:1234, it'll actually be connecting to a \"different\" 127.0.0.1 from another process on your machine listening on this same address and port, and you won't be able to connect.\n\nAs a workaround, the address 169.254.77.65 is hardcoded within httptap to route to 127.0.0.1.\n\n# Subprocesses that daemonize\n\nIn linux, it is possible for a process to create subprocesses that stick around even when the original process exits. This is standard practice for daemons and also for GUI apps launched from the command line. If you run a process that daemonizes under httptap, the daemonized process will still be in httptap's network namespace, but you will need to use `--no-exit` to make sure that httptap keeps proxying and logging traffic even after the immediate subprocess exits. For example, here is visual studio code running within httptap:\n\n```bash\n$ httptap --no-exit -- code --ignore-certificate-errors .\n---> OPTIONS https:\u002F\u002Fdefault.exp-tas.com\u002Fvscode\u002Fab\n\u003C--- 204 https:\u002F\u002Fdefault.exp-tas.com\u002Fvscode\u002Fab (0 bytes)\n---> GET https:\u002F\u002Fdefault.exp-tas.com\u002Fvscode\u002Fab\n\u003C--- 304 https:\u002F\u002Fdefault.exp-tas.com\u002Fvscode\u002Fab (0 bytes)\n...\n```\n\nYou will have to press Ctrl+C to kill httptap once you exit vscode.\n\nIn the above, without `--no-exit`, httptap would exit immediately after launching vscode. However, even though the subprocess launched by httptap has exited, that subprocess created a whole separate process tree before it did so. That process tree is the actual GUI app, and it is still pinned to the httptap network namespace. If httptap exits then the network namespace will continue to exist, and the GUI app will continue to run, but nobody will be reading packets sent to the TUN device that is only available network interface in that network namespace, and as a result the app will have no network connectivity. The workaround for this is the `--no-exit` flag that asks httptap to keep proxying network traffic even after the immediate subprocess exits.\n\nA more minimal example of this same phenomenon is:\n```bash\n$ httptap --no-exit -- setsid setsid curl http:\u002F\u002Fhttpbin.org\u002Fget\n---> GET http:\u002F\u002Fhttpbin.org\u002Fget\n\u003C--- 200 http:\u002F\u002Fhttpbin.org\u002Fget (285 bytes)\n```\n\nWithout the `--no-exit` flag, the above fails:\n```bash\n$ httptap -- setsid setsid curl http:\u002F\u002Fhttpbin.org\u002Fget\ncurl: (6) Could not resolve host: httpbin.org\n```\n\nA python example that illustrates what syscalls are at play is:\n```bash\n$ $ httptap --no-exit -- python -c 'import os; import sys; import subprocess\nif os.fork(): sys.exit()\nos.setsid()\nif os.fork(): sys.exit()\nsubprocess.run([\"curl\", \"http:\u002F\u002Fhttpbin.org\u002Fget\"])'\n---> GET http:\u002F\u002Fhttpbin.org\u002Fget\n\u003C--- 200 http:\u002F\u002Fhttpbin.org\u002Fget (285 bytes)\n```\n\nAgain, without `--no-exit`, the above fails:\n```bash\n$ httptap -- python -c 'import os; import sys; import subprocess\nif os.fork(): sys.exit()\nos.setsid()\nif os.fork(): sys.exit()\nsubprocess.run([\"curl\", \"http:\u002F\u002Fhttpbin.org\u002Fget\"])'\ncurl: (6) Could not resolve host: httpbin.org\n```\n\n# How it works\n\nWhen you run `httptap -- \u003Ccommand>`, httptap runs `\u003Ccommand>` in an isolated network namespace, injecting a certificate authority created on-the-fly in order to decrypt HTTPS traffic. Here is the process in detail:\n\nIn linux, there is a kernel API for creating and configuring network interfaces. Conventionally, a network interface would be a physical ethernet or WiFi controller in your computer, but it is possible to create a special kind of network interface called a TUN device. A TUN device shows up to the system in the way that any network interface shows up, but any traffic written to it will be delivered to a file descriptor held by the process that created it. Httptap creates a TUN device and runs the subprocess in an environment in which all network traffic is routed through that device.\n\nThere is also a kernel API in linux for creating network namespaces. A network namespace is a list of network interfaces and routing rules. When a process is started in linux, it can be run in a specified network namespace. By default, processes run in a root network namespace that we do not want to make changes to because doing so would affect all network traffic on the system. Instead, we create a network namespace in which there are only two network interfaces: a loopback device (127.0.0.1) and a TUN device that delivers traffic to us. Then we run the subprocess in that namespace.\n\nThe traffic from the network device is delivered to us as raw IP packets. We must parse the IP packets as well as the inner TCP and UDP packets, and write raw IP packets back to the subprocess. This requires a software implementation of the TCP\u002FIP protocol, which is by far the most difficult part of httptap. The TCP\u002FIP implementation in httptap is missing many aspects of the full TCP protocol, but still works reasonably well for its purpose.\n\nSuppose the subprocess makes an HTTP request to www.example.com. The first thing we receive is a TCP SYN packet addressed to 93.184.215.14 (the current IP address of example.com). We respond with a SYN+ACK packet with source address 93.184.215.14, though in truth the packet did not come from 93.184.215.14, but from us. Separately, we establish our own TCP connection to 93.184.215.14 using the ordinary sockets API in the linux kernel. When the subprocess sends data to 93.184.215.14 we relay it over our separate TCP connection, and vice versa for return data. This is a traditional transparent TCP proxy, and in this way we can view all data flowing to and from the subprocess, though we won't be able to decrypt HTTPS traffic without a bit more work.\n\nWhen a client makes an HTTPS request, it asks the server for evidence that it is who it says it is. If the server has a certificate signed by a certificate authority, it can use that certificate to prove that it is who it says it is. The client will only accept such a certificate if it trusts the certificate authority that signed the certificate. Operating systems, web browsers, and many other pieces of software come with a list of a few hundred certificate authorities that they trust. Many of these pieces of software have ways for users to add additional certificate authorities to this list. We make use of this.\n\nWhen httptap starts, it creates a certificate authority (actually a private key plus a corresponding x509 certificate), writes it to a file on the filesystem visible only to the subprocess, and sets a few environment variables -- again only visible to the subprocess being run -- that add this certificate authority to the list of trusted certificate authorities. Since the subprocess trusts this certificate authority, and httptap holds the private key for the certificate authority, it can prove to the subprocess that it is the server which the subprocess was trying to communicate. In this way we can read the plaintext HTTP requests.\n\n# How it was made\n\nHttptap is part of an experiment in developing technology in the context of Buddhist monasticism. It was developed at the [Monastic Academy](https:\u002F\u002Fwww.monasticacademy.org) in Vermont in the US. We believe that a monastic schedule, and the practice of the Buddhist spiritual path more generally, provide ideal conditions for technological development. The way we have set things up is that we live and practice together on a bit over a hundred acres of land. In the mornings and evenings we chant and meditate together, and for about one week out of every month we run and participate in a meditation retreat. The rest of the time we work together on everything from caring for the land, maintaining the buildings, cooking, cleaning, planning, fundraising, and for the past few years developing software together. This project is a demonstration of what is possible on the software side, but of course to see the full product of our work you should come visit us.\n\nIf you're interested, we run an [AI fellowship program](https:\u002F\u002Fwww.monasticacademy.org\u002Fai-fellowship), which is a funded month-to-month program where you live on the land, participate in the schedule, and do your own work during the day. We also have a 3-month [monastic training program](https:\u002F\u002Fwww.monasticacademy.org\u002Ftrain), which can lead into our long-term residential training.\n\nFor the past few years we have been recording a lecture series called [Buddhism for AI](https:\u002F\u002Fbuddhismforai.sutra.co). It's about our efforts to design a religion (yes, a religion) based on Buddhism for consumption directly by AI systems. We actually feel this is very important work given the world situation.\n\nFinally, our head teacher [Soryu Forall](https:\u002F\u002Fwww.monasticacademy.org\u002Fteacher) published a book a few years back called [Buddhism For All](https:\u002F\u002Fbuddhism.net\u002Fbuddhism-for-all-book\u002F). We're working on a sequel at the moment.\n\n![MAPLE Group Photo](docs\u002Fgroup.webp)\n\n# Caveats\n\n- The process cannot listen for incoming network connections\n- You need access to `\u002Fdev\u002Fnet\u002Ftun`\n- All ICMP echo requests will be echoed without sending any ICMP packets out to the real network\n\n# Donations\n\nYou can support [me personally through github sponsors](https:\u002F\u002Fgithub.com\u002Fsponsors\u002Falexflint), or (my preference if it's an option for you) [the community I live in through our donate page](https:\u002F\u002Fwww.monasticacademy.org\u002Fdonate).","httptap 是一个用于查看任何 Linux 程序发出的 HTTP\u002FHTTPS 请求的工具。它通过运行 `httptap -- \u003Ccommand>` 来拦截并显示指定命令执行过程中的网络请求及其响应，支持直接从终端输出这些信息而无需额外配置或以 root 用户身份操作。该工具利用了 Go 语言编写为静态二进制文件，确保跨平台兼容性的同时保持轻量级，并且特别依赖于 Linux 系统调用和网络命名空间技术来实现其功能。适用于需要监控、调试或审计应用程序网络行为的各种开发与运维场景中。","2026-06-11 03:44:36","high_star"]