Crate rama

source ·
Expand description

🦙 Rama (ラマ) is a modular service framework for the 🦀 Rust language to move and transform your network packets. The reasons behind the creation of rama can be read in the “Why Rama” chapter.

Rama is async-first using Tokio as its only Async Runtime. Please refer to the examples found in the /examples dir to get inspired on how you can use it for your purposes.

This framework comes with 🔋 batteries included, giving you the full freedome to build the middleware and services you want, without having to repeat the “common”:

categorysupport list
🏗️ transports✅ tcp ⸱ 🏗️ udp (1) ⸱ ✅ middleware
🏗️ http✅ auto ⸱ ✅ http/1.1 ⸱ ✅ h2 ⸱ 🏗️ h3 (1) ⸱ ✅ middleware
✅ web server✅ fs ⸱ ✅ redirect ⸱ ✅ dyn router ⸱ ✅ static router ⸱ ✅ handler extractors ⸱ ✅ k8s healthcheck
✅ http client✅ client ⸱ ✅ high level API ⸱ ✅ Proxy Connect ⸱ ❌ Chromium Http (3)
🏗️ tls✅ Rustls ⸱ 🏗️ BoringSSL (1) ⸱ ❌ NSS (3)
✅ dns✅ DNS Resolver
✅ proxy protocols✅ PROXY protocol ⸱ ✅ http proxy ⸱ ✅ https proxy ⸱ 🏗️ SOCKS5 (2) ⸱ 🏗️ SOCKS5H (2)
🏗️ web protocols🏗️ Web Sockets (WS) (2) ⸱ 🏗️ WSS (2) ⸱ ❌ Web Transport (3) ⸱ ❌ gRPC (3)
✅ async-method trait services✅ Service ⸱ ✅ Layer ⸱ ✅ context ⸱ ✅ dyn dispatch ⸱ ✅ middleware
✅ [telemetry][opentelemetry]✅ tracing ⸱ ✅ [opentelemetry] ⸱ ✅ http metrics ⸱ ✅ transport metrics ⸱ ✅ prometheus exportor
✅ upstream proxies✅ MemoryProxyDB ⸱ ✅ L4 Username Config ⸱ ✅ Proxy Filters
🏗️ User Agent (UA)🏗️ Http Emulation (1) ⸱ 🏗️ Tls Emulation (1) ⸱ ✅ UA Parsing
🏗️ utilities✅ error handling ⸱ ✅ graceful shutdown ⸱ 🏗️ Connection Pool (1) ⸱ 🏗️ IP2Loc (2)
🏗️ TUI🏗️ traffic logger (2) ⸱ 🏗️ curl export (2) ⸱ ❌ traffic intercept (3) ⸱ ❌ traffic replay (3)
✅ binary✅ prebuilt binaries ⸱ 🏗️ proxy config (2) ⸱ ✅ http client (1) ⸱ ❌ WASM Plugins (3)
🏗️ data scraping🏗️ Html Processor (2) ⸱ ❌ Json Processor (3)
❌ browser❌ JS Engine (3) ⸱ ❌ Web API Emulation (3)

🗒️ Footnotes

The primary focus of Rama is to aid you in your development of proxies:

💡 Check out the “Intro to Proxies” chapters in the Rama book to learn more about the different kind of proxies. It might help in case you are new to developing proxies.

The Distortion proxies support comes with User Agent (UA) emulation capabilities. The emulations are made possible by patterns and data extracted using rama-fp. The service is publicly exposed at https://fp.ramaproxy.org, made possible by our sponsor host https://fly.io/.

🔁 https://echo.ramaproxy.org/ is another service publicly exposed. In contrast to the Fingerprinting Service it is aimed at developers and allows you to send any http request you wish in order to get an insight on the Tls Info and Http Request Info the server receives from you when making that request.

curl -XPOST 'https://echo.ramaproxy.org/foo?bar=baz' \
  -H 'x-magic: 42' --data 'whatever forever'

Feel free to make use of while crafting distorted http requests, but please do so with moderation. In case you have ideas on how to improve the service, please let us know by opening an issue.

BrowserStack sponsors Rama by providing automated cross-platform browser testing on real devices, which uses the public fingerprinting service to aid in automated fingerprint collection on both the Http and Tls layers. By design we do not consider Tcp and Udp fingerprinting.

Next to proxies, Rama can also be used to develop Web Services and Http Clients.

📖 Rama’s full documentation, references and background material can be found in the form of the “rama book” at https://ramaproxy.org/book.

💬 Come join us at Discord on the #rama public channel. To ask questions, discuss ideas and ask how rama may be useful for you.

rama banner

§🧪 | Experimental

🦙 Rama (ラマ) is to be considered experimental software for the foreseeable future. In the meanwhile it is already used in production by ourselves and others alike. This is great as it gives us new perspectives and data to further improve and grow the framework. It does mean however that there are still several non-backward compatible releases that will follow 0.2.

In the meanwhile the async ecosystem of Rust is also maturing, and edition 2024 is also to be expected as a 2024 end of year gift. It goes also without saying that we do not nilly-willy change designs or break on purpose. The core design is by now also well defined. But truth has to be said, there is still plenty to be improve and work out. Production use and feedback from you and other users helps a lot with that. As such, if you use Rama do let us know feedback over Discord, email or a GitHub issue.

👉 If you are a company or enterprise that makes use of Rama, or even an individual user that makes use of Rama for commcercial purposes. Please consider becoming a business/enterprise subscriber. It helps make the development cycle to remain sustainable, and is beneficial to you as well. As part of your benefits we are also available to assist you with migrations between breaking releases. For enterprise users we can even make time to develop those PR’s in your integration codebases ourselves on your behalf. A win for everybody. 💪

§🏢 | Proxy Examples

  • /examples/tls_termination.rs: Spawns a mini handmade http server, as well as a TLS termination proxy, forwarding the plain text stream to the first.
  • /examples/tls_termination.rs: Spawns a mini handmade http server, as well as a TLS termination proxy, forwarding the plain text stream to the first.
  • /examples/mtls_tunnel_and_service.rs: Example of how to do mTls (manual Tls, where the client also needs a certificate) using rama, as well as how one might use this concept to provide a tunnel service build with these concepts;
  • /examples/http_connect_proxy.rs: Spawns a minimal http proxy which accepts http/1.1 and h2 connections alike, and proxies them to the target host.

§🌐 | Web Services

Developing proxies are the primary focus of Rama (ラマ). It can however also be used to develop web services to serve web pages, Http API’s and static content. This comes with many of the same benefits that you get when developing proxies using Rama:

  • Use Async Method Traits;
  • Reuse modular Tower-like middleware using extensions as well as strongly typed state;
  • Have the ability to be in full control of your web stack from Transport Layer (Tcp, Udp), through Tls and Http;
  • If all you care about is the Http layer then that is fine to.
  • Be able to trust that your incoming Application Http data has not been modified (e.g. Http header casing and order is preserved);
  • Easily develop your service at a Request layer and High level functions alike, choices are yours and can be combined.

Examples of the kind of web services you might build with rama in function of your proxy service:

  • a k8s health service (/examples/http_k8s_health.rs);
  • a metric exposure service;
  • a minimal api service (e.g. to expose device profiles or certificates);
  • a graphical interface / control panel;

📖 Learn more about developing web services in the Rama book: https://ramaproxy.org/book/web_servers.html.

§🌐 | Web Service Examples

Here are some low level web service examples without fancy features:

  • /examples/http_listener_hello.rs: is the most basic example on how to provide a root service with no needs for endpoints or anything else (e.g. good enough for some use cases related to health services or metrics exposures);
  • /examples/http_service_hello.rs: is an example similar to the previous example but shows how you can also operate on the underlying transport (TCP) layer, prior to passing it to your http service;

There’s also a premade webservice that can be used as the health service for your proxy k8s workloads:

The following are examples that use the high level concepts of Request/State extractors and IntoResponse converters, that you’ll recognise from axum, just as available for rama services:

For a production-like example of a web service you can also read the rama-fp source code. This is the webservice behind the Rama fingerprinting service, which is used by the maintainers of 🦙 Rama (ラマ) to generate the UA emulation data for the Http and TLS layers. It is not meant to fingerprint humans or users. Instead it is meant to help automated processes look like a human.

💡 This example showcases how you can make use of the match_service macro to create a Box-free service router. Another example of this approach can be seen in the http_service_match.rs example.

§🧑‍💻 | Http Clients

In The rama book you can read and learn that a big pilar of Rama’s architecture is build on top of the Service concept. A Service takes as input a user-defined State (e.g. containing your database Pool) and a Request, and uses it to serve either a Response or Error. Such a Service can produce the response “directly” (also called ☘️ Leaf services) or instead pass the request and state to an inner Service which it wraps around (so called 🍔 Middlewares).

It’s a powerful concept, originally introduced to Rust by the Tower ecosystem and allows you build complex stacks specialised to your needs in a modular and easy manner. Even cooler is that this works for both clients and servers alike.

Rama provides an HttpClient which sends your Http Request over the network and returns the Response if it receives and read one or an Error otherwise. Combined with the many Layers (middleware) that Rama provides and perhaps also some developed by you it is possible to create a powerful Http client suited to your needs.

As a 🍒 cherry on the cake you can import the HttpClientExt trait in your Rust module to be able to use your Http Client Service stack using a high level API to build and send requests with ease.

§🧑‍💻 | Http Client Example

💡 The full example can be found at /examples/http_high_level_client.rs.

ⓘ
use rama::http::client::HttpClientExt;

let client = ServiceBuilder::new()
    .layer(TraceLayer::new_for_http())
    .layer(DecompressionLayer::new())
    .layer(
        AddAuthorizationLayer::basic("john", "123")
            .as_sensitive(true)
            .if_not_present(),
    )
    .layer(RetryLayer::new(
        ManagedPolicy::default().with_backoff(ExponentialBackoff::default()),
    ))
    .service(HttpClient::default());

#[derive(Debug, Deserialize)]
struct Info {
    name: String,
    example: String,
    magic: u64,
}

let info: Info = client
    .get("http://example.com/info")
    .header("x-magic", "42")
    .typed_header(Accept::json())
    .send(Context::default())
    .await
    .unwrap()
    .try_into_json()
    .await
    .unwrap();

Modules§

  • rama cli utilities
  • DNS module for Rama.
  • Error utilities for rama and its users.
  • Rama http modules.
  • protocol agnostic network modules
  • Upstream proxy types and utilities.
  • Runtime utilities used by Rama.
  • async fn serve(&self, Context<S>, Request) -> Result<Response, Error>
  • TCP module for Rama.
  • Rama telemetry modules.
  • TLS module for Rama.
  • User Agent (UA) parser and types.
  • Utilities in service of the Rama project.