rust

Creating a web service in Rust and running it in WebAssembly

In this blog post, I will show you how to create a simple web service in Rust and compile it to Wasm. Then, I will show you how to run the Wasm service on the server using a Wasm runtime.

Creating a web service

To create a web service in Rust, we will use the hyper crate, which is a fast and low-level HTTP library. Hyper provides both server and client APIs for working with HTTP requests and responses. To use hyper, we need to add it as a dependency in our Cargo.toml file:

[dependencies]
hyper = "0.14"

Then, we can write our web service code in the src/main.rs file. The code below creates a simple web service that responds with “Hello, World!” to any GET request:

use hyper::{Body, Request, Response, Server};
use hyper::service::{make_service_fn, service_fn};
use std::convert::Infallible;
// A function that handles an incoming request and returns a response
async fn hello_world(_req: Request) -> Result, Infallible> {
Ok(Response::new(Body::from("Hello, World!")))
}
#[tokyo::main]
async fn main() {
// Bind the server to an address
let addr = ([127, 0, 0, 1], 3000).into();
// Create a service function that maps each connection to a hello_world function
let make_service = make_service_fn(|conn| async { Ok::<, Infallible>(service_fn(hello_world))
});
// Create a server with the service function
let server = Server::bind(&addr).serve(make_service);
// Run the server and handle any error
if let Err(e) = server.await {
eprintln!("server error: {}", e);
}
}

To run the web service locally, we can use the cargo run command in the terminal. This will compile and execute our Rust code. We can then test our web service by sending a GET request using curl or a web browser:

$ curl http://localhost:3000
Hello, World!

Creating a web service client

To demonstrate how to use hyper as a web service client, we can write another Rust program that sends a GET request to our web service and prints the response body. The code below shows how to do this using the hyper::Client struct:

use hyper::{Body, Client};
use hyper::body::HttpBody as _;
#[tokyo::main]
async fn main() {
// Create a client
let client = Client::new();
// Send a GET request to the web service
let uri = "http://localhost:3000".parse().unwrap();
let mut resp = client.get(uri).await.unwrap();
// Print the status code and headers
println!("Response: {}", resp.status());
println!("Headers: {:#?}\n", resp.headers());
// Print the response body
while let Some(chunk) = resp.body_mut().data().await {
let chunk = chunk.unwrap();
println!("{}", std::str::from_utf8(&chunk).unwrap());
}
}

To run the web service client locally, we can use the cargo run command in another terminal. This will compile and execute our Rust code. We should see something like this:

$ cargo run
Response: 200 OK
Headers: {
"content-length": "13",
}
Hello, World!

Creating a database client


To make our web service more useful, we can add some database functionality to it. For example, we can store and retrieve some data from a MySQL database using the mysql_async crate, which is an asynchronous MySQL driver based on tokio. To use mysql_async, we need to add it as a dependency in our Cargo.toml file:

[dependencies]
mysql_async = "0.28"

Then, we can modify our web service code in the src/main.rs file to connect to a MySQL database and execute some queries. The code below assumes that we have a MySQL database running on localhost with the default port (3306), username (root), password (password), and database name (test). The code also assumes that we have a table called users with two columns: id (int) and name (varchar).

use hyper::{Body, Request, Response, Server};
use hyper::service::{make_service_fn, service_fn};
use mysql_async::{Pool, Row};
use std::convert::Infallible;
// A function that handles an incoming request and returns a response
async fn hello_world(_req: Request) -> Result, Infallible> {
// Create a pool of connections to the MySQL database
let pool = Pool::new("mysql://root:password@localhost:3306/test");
// Get a connection from the pool
let mut conn = pool.get_conn().await.unwrap();
// Execute a query to insert a new user
conn.exec_drop("INSERT INTO users (name) VALUES (?)", ("Alice",)).await.unwrap();
// Execute a query to select all users
let users: Vec = conn.query("SELECT id, name FROM users").await.unwrap();
// Drop the connection and return it to the pool
drop(conn);
// Format the users as a string
let mut output = String::new();
for user in users {
let (id, name) = mysql_async::from_row(user);
output.push_str(&format!("User {}: {}\n", id, name));
}
// Return the output as the response body
Ok(Response::new(Body::from(output)))
}
#[tokyo::main]
async fn main() {
// Bind the server to an address
let addr = ([127, 0, 0, 1], 3000).into();
// Create a service function that maps each connection to a hello_world function
let make_service = make_service_fn(|conn| async { Ok::<, Infallible>(service_fn(hello_world))
});
// Create a server with the service function
let server = Server::bind(&addr).serve(make_service);
// Run the server and handle any error
if let Err(e) = server.await {
eprintln!("server error: {}", e);
}
}

To run the web service locally, we can use the cargo run command in the terminal. This will compile and execute our Rust code. We can then test our web service by sending a GET request using curl or a web browser:

$ curl http://localhost:3000
User 1: Alice
User 2: Alice
User 3: Alice

Building and running the web service

To build our web service as a Wasm binary, we need to use the cargo-wasi crate, which is a Cargo subcommand for building Rust code for Wasm using the WebAssembly System Interface (WASI). WASI is a standard interface for Wasm programs to access system resources such as files, network, and environment variables. To install cargo-wasi, we can use the cargo install command:

$ cargo install cargo-wasi

Then, we can use the cargo wasi build command to build our web service as a Wasm binary. This will create a target/wasm32-wasi/debug directory with our Wasm binary file:

$ cargo wasi build
Compiling hyper v0.14.15
Compiling mysql_async v0.28.0
Compiling wasm-service v0.1.0 (/home/user/wasm-service)
Finished dev [unoptimized + debuginfo] target(s) in 1m 23s

To run our web service as a Wasm binary on the server, we must use a Wasm runtime that supports WASI and network features. There are several Wasm runtimes available, such as Wasmtime, Wasmer, and WasmEdge. In this blog post, I will use WasmEdge as an example.

To install WasmEdge follow the instructions on its website.

Then, we use the wasmedge command to run our web service as a Wasm binary. We need to pass some arguments to enable WASI and network features and to bind our web service to an address:

$ wasmedge --dir .:. --dir /tmp:/tmp --net 127.0.0.1:3000 target/wasm32-wasi/debug/wasm_service.wasm --addr 127.0.0.1:3000

We can then test our web service by sending a GET request using curl or a web browser:

$ curl http://localhost:3000
User 1: Alice
User 2: Alice
User 3: Alice

Conclusion

Here we’ve created a simple web service in Rust and compiled it to Wasm. I have also shown you how to run the Wasm service on the server using a Wasm runtime. I hope you have enjoyed this tutorial and learned something new.

Creating a web service in Rust and running it in WebAssembly Read More »

Review of RustRover: A New IDE for Rust developers by JetBrains

Rust is a popular programming language that offers high performance, reliability, and memory safety. Rust is widely used for system programming, web development, embedded systems, and more. However, Rust also has a steep learning curve and requires a lot of tooling and configuration to get started. This is where an integrated development environment (IDE) can help.

JetBrains is a well-known company that produces many popular IDEs for various languages and technologies, such as IntelliJ IDEA for Java, PyCharm for Python, CLion for C/C++, and WebStorm for web development. JetBrains has recently announced the preview of RustRover, a standalone IDE for Rust that aims to provide a full-fledged Rust development environment with smart coding assistance, seamless toolchain management, and team collaboration.

I will review RustRover based on the following criteria:

  • Installation and setup
  • User interface and usability
  • Features and functionality
  • Performance and stability
  • Pricing and licensing

Installation and setup

To install RustRover, you can visit the JetBrains website and download the installer for your operating system (Windows, macOS, or Linux). The installation process is straightforward and does not require any additional steps or configurations. You can also install RustRover as a plugin in IntelliJ IDEA Ultimate or CLion if you prefer.

To start using RustRover, you need to have the Rust toolchain installed on your machine. RustRover can detect the existing toolchain or help you install it if you don’t have one. You can also choose which toolchain version (stable, beta, or nightly) you want to use for your projects.

To create a new project in RustRover, you can use the built-in wizard that guides you through the process. You can choose from various project templates based on Cargo, the official package manager and build system for Rust. You can also import an existing project from a local directory or a version control system such as Git or GitHub.

User interface and usability

RustRover has a user interface that is similar to other JetBrains IDEs. It has a main editor area where you can write and edit your code, a project explorer where you can browse your files and folders, a toolbar where you can access various actions and commands, and several tool windows where you can view additional information and tools such as Cargo commands, run configurations, test results, debug console, terminal, etc.

RustRover has a dark theme by default, but you can change it to a light theme or customize it according to your preferences. You can also adjust the font size, color scheme, editor layout, keymap, plugins, and other settings in the preferences menu.

RustRover has a high usability level as it provides many features and tools that make the coding experience easier and faster. For example, you can use keyboard shortcuts to perform common tasks such as running or debugging your code, formatting or refactoring your code

Some examples of how the IDE is used for quick development are:

  • Creating a new project from a template: RustRover provides various project templates based on Cargo, the official package manager and build system for Rust. You can choose from templates such as Binary, Library, WebAssembly, or Custom. RustRover will automatically generate the necessary files and configurations for your project, such as Cargo.toml, src/main.rs, or src/lib.rs. You can also import an existing project from a local directory or a version control system.
  • Writing and editing code with smart assistance: RustRover provides many features and tools that make the coding experience easier and faster. For example, you can use code completion, syntax highlighting, inlined hints, macro expansion, quick documentation, quick definition, and more. RustRover also provides code analysis and error reporting, which can detect and fix problems in your code. You can also use code formatting, refactoring, and generation to improve the quality and structure of your code.
  • Running and debugging code with ease: RustRover allows you to run and debug your code with just one click or shortcut. You can use the Run tool window to view the output of your program, or the Debug tool window to inspect the state of your program. You can also use breakpoints, stepping, watches, evaluations, and more to control the execution flow and examine the variables and expressions. RustRover also supports debugging tests, benchmarks, and WebAssembly modules.
  • Testing and profiling code with confidence: RustRover supports testing and profiling your code using various tools and frameworks. You can use the Test Runner to run and debug your tests, view the test results, filter and sort the tests, and create test configurations. You can also use the Code Coverage tool to measure how much of your code is covered by tests. RustRover also integrates with external profilers such as perf or Valgrind to help you analyze the performance and memory usage of your code.
  • Working with version control systems and remote development: RustRover supports working with various version control systems such as Git or GitHub. You can use the Version Control tool window to view the history, branches, commits, changes, and conflicts of your project. You can also use the VCS operations popup to perform common actions such as commit, push, pull, merge, rebase, etc. RustRover also supports remote development using SSH or WSL. You can connect to a remote server and code, run, debug, and deploy your projects remotely

Features of RustRover

RustRover aims to simplify the Rust coding experience while unlocking the language’s full potential. Some of the features of RustRover are:

  • Syntax highlighting: RustRover highlights all elements of your Rust code, including inferred types and macros, cfg blocks, and unsafe code usages.
  • On-the-fly analysis: RustRover analyzes your code as you type and suggests quick fixes to resolve the problems automatically.
  • Macro expansion: RustRover’s macro expansion engine makes macros transparent to code insight and easier for you to explore. You can select a declarative macro and call either a one-step or a full expansion view.
  • Code generation: RustRover helps you save time on typing by generating code for you. You can add missing fields and impl blocks, import unresolved symbols, or insert the code templates you use frequently.
  • Completion: RustRover provides relevant completion suggestions everywhere in your code, even inside a macro call or #[derive].
  • Navigation & Search: RustRover helps you navigate through code structures and hierarchies with various Go-To actions, accessible via shortcuts and gutter icons. For example, Go to Implementation lets you quickly switch between traits, types, and impls. You can also use Find Usages to track all the occurrences of a symbol in your code.
  • Cargo support: RustRover fully integrates with Cargo, the official package manager for Rust. The IDE extracts project information from your Cargo.toml files and provides a wizard to create new Cargo-based projects. You can also call Cargo commands right from the IDE, and the dedicated tool window will help you manage the entire workspace.
  • Testing: RustRover makes it easy to start tests and explore the results. You can call cargo test or use the gutter menu, and the IDE will use its own test runner to show you the process. After the tests are finished, you will see a tree view of the results. You can sort it, export test data, and jump back to the code.
  • Run, Debug, Analyze: You can get full IDE debugging for your Rust applications in RustRover. You can set breakpoints, step through your code, inspect raw memory, and use many other debug essentials. The IDE’s native type renderers build tree-view representations for most of the Rust types, including strings, structs, enums, vectors, and other standard library types. You can also use Run Targets to run or debug your applications on different platforms or environments, such as Docker containers or remote hosts. Additionally, you can use Code Coverage to measure how much of your code is covered by tests.
  • HTTP Client: RustRover comes with a built-in HTTP client that lets you analyze requests and responses for your web applications. You can write HTTP requests in a dedicated scratch file or in any file that supports injections. You can then run them from the editor or from the HTTP Requests tool window. The IDE will show you the response status code, headers, body, cookies, and timings. You can also compare responses or save them for later use.
  • Code With Me: RustRover supports Code With Me, a service that allows you to share your project with others and collaborate on it in real-time. You can invite your teammates or clients to join your session via a link or an email invitation. You can then work on the same codebase simultaneously, chat with each other via audio or video calls or text messages, share your local servers or terminals, and debug together.

Performance of RustRover

RustRover is designed to be fast and responsive even for large and complex projects. The IDE uses incremental compilation and caching to speed up the build process and reduce resource consumption. The IDE also leverages the power of the IntelliJ platform’s indexing mechanism to provide fast and accurate code analysis and navigation. RustRover also supports the experimental rust-analyzer engine, which is a new language server implementation for Rust that aims to provide better performance and scalability.

Pricing of RustRover

RustRover is currently in preview and is free to use during the public preview period. The license model and the pricing will be finalized closer to the date of the commercial release, which is expected to be before September 2024. JetBrains plans to offer RustRover as a standalone commercial IDE or as part of the All Products Pack, which includes access to all JetBrains IDEs and tools. They say that the development of the currently available Rust plugin for CLion and IntelliJ IDEs has ceased and this tool will not be actively supported going forward, being replaced by commercial RustRover IDE. JetBrains also offers discounts and free licenses for students, teachers, open-source contributors, startups, and non-commercial organizations.

Conclusion

RustRover is a new IDE for Rust developers that offers a comprehensive and integrated development environment. RustRover simplifies the Rust coding experience with features such as smart coding assistance, seamless Cargo support, a built-in test runner, and code coverage tooling. RustRover also provides advanced functionality such as debugging, run targets, HTTP client, and “code with me”. RustRover is based on the IntelliJ platform and inherits many features from other JetBrains IDEs.

If you are interested in trying out RustRover, you can download it from the official website or from the JetBrains Toolbox App. You can also read more about RustRover on the IntelliJ Rust blog or watch the video introduction. You can also join the RustRover Early Access Program (EAP) and give your feedback and suggestions to help shape the product. You can report issues or feature requests on the issue tracker or on the forum. You can also follow RustRover on Twitter for the latest news and updates.

We hope you enjoy using RustRover and find it useful for your Rust development needs. Happy coding!

Review of RustRover: A New IDE for Rust developers by JetBrains Read More »

Why Rust is a Good Fit for Creating Malware

Malware developers and hackers are always looking for new ways and tools to create and deploy malware that can evade detection and analysis by security tools and experts. One of the tools that has been gaining popularity among malware developers and hackers is Rust, a programming language that was created by Mozilla in 2010.

Rust is a low-level language that can run close to the hardware and offer high performance and efficiency. Rust is also a memory-safe language that prevents common errors and vulnerabilities, such as buffer overflows, memory leaks, and null pointers. Rust is also a cross-platform language that can run on any operating system and architecture. Rust can also compile to WebAssembly (Wasm), a binary format that can run on any platform and environment.

In this blog post, we will explore how Rust can be a good fit for creating malware by discussing four aspects: performance, security, portability, and evasiveness.

Performance

One of the advantages of Rust is that it can offer high performance and efficiency for malware development and execution. Rust can leverage native code and hardware acceleration to optimize the speed and power of malware. For example, the 3AM ransomware, which was written in Rust, used the AES-NI instruction set to encrypt files faster. Rust can also reduce the size and resource consumption of malware by using a compact and efficient binary format. For example, the Buer loader, which was rewritten in Rust, reduced its size from 150 KB to 30 KB.

Security

Another advantage of Rust is that it can provide security and isolation for malware development and execution. Rust can prevent common errors and vulnerabilities that may expose or compromise the malware code or data. For example, Rust can prevent buffer overflows that may allow attackers to inject or execute malicious code on the target system. Rust can also provide security and isolation for malware execution by running it in a sandboxed environment. For example, the BlackCat ransomware, which was written in Rust, used the seccomp system call to restrict the access of the malware process to the kernel.

Portability

A third advantage of Rust is that it can provide portability and compatibility for malware development and execution. Rust can run on any operating system and architecture without requiring any changes or modifications to the code. For example, the Hive ransomware, which was written in Rust, could target Windows, Linux, macOS, Android, iOS systems. Rust can also compile to WebAssembly (Wasm), which can run on any platform and environment without requiring any installation or configuration. For example, the Hive ransomware used Wasm to target Linux systems.

Evasiveness

A fourth advantage of Rust is that it can provide evasiveness and stealthiness for malware development and execution. Rust is a relatively new language that can evade the detection and analysis of malware by security tools and experts. For example, many antivirus programs do not recognize or scan Rust binaries or Wasm files. Rust can also obfuscate and encrypt the code and data of malware to make it harder to reverse engineer or decrypt. For example, the Buer loader used XOR encryption and compression to hide its payload.

Conclusion

Rust is a programming language that has been gaining popularity among developers and hackers alike. Being a language for system and low-level development, Rust is a good fit for creating malware for several reasons: performance, security, portability, small size of binaries, and the “surprise” effect of Rust-based malware. 3AM ransomware is just one example of Rust-based malware that was recently detected by security researchers.

Why Rust is a Good Fit for Creating Malware Read More »