Thanks for considering contributing! This document covers the practical stuff you need to know.
git clone https://github.com/vdavid/smb2
cd smb2
cargo build
cargo testYou don't need an SMB server for most development. The test suite uses mock transports for protocol logic.
We use just as a command runner. Install it, then:
just # Run all checks: format, lint, test, doc
just fix # Auto-fix formatting and clippy warnings
just check-all # Include MSRV check, security audit, and license checkRun just --list to see all available commands.
We support Rust 1.85. Before submitting PRs, verify MSRV compatibility:
rustup toolchain install 1.85.0 # One-time setup
just msrv # Check MSRV compatibilityThis catches issues that only appear on older Rust versions. CI runs this check, so just msrv locally saves a round-trip.
src/
├── lib.rs # Crate root
├── error.rs # Error types, NTSTATUS mapping
├── pack/ # Binary serialization (ReadCursor, WriteCursor)
├── types/ # Newtypes (SessionId, TreeId, FileId, etc.)
├── msg/ # Wire format message structs
├── transport/ # Transport trait, TCP implementation, mock
├── crypto/ # Signing, encryption, key derivation
├── auth/ # NTLM authentication
└── client/ # High-level API (SmbClient, Tree, Pipeline)
tests/
├── pack_roundtrip.rs # Property-based tests for pack/unpack
├── msg_wire_format.rs # Test messages against known byte sequences
├── protocol_flow.rs # Full protocol flows with mock transport
└── integration.rs # Tests against real Samba server (Docker)
# Unit tests (no server needed)
cargo test
# Integration tests (requires Docker Samba)
cargo test --test integration -- --ignored --nocaptureIntegration tests need a Samba server running in Docker. See the test file for setup instructions.
We follow standard Rust conventions with a few specific choices:
#![forbid(unsafe_code)]: no unsafe code, ever#![warn(missing_docs)]: doc comments for all public APIs- Hand-rolled binary serialization (no proc macros for wire format)
- Newtypes for protocol IDs (
SessionId,TreeId,FileId, etc.) thiserrorfor error types
The quick version:
- Run
justbefore committing (orjust fixto auto-fix issues) - Tests for new functionality
- Doc comments for public APIs
A few things that might not be obvious:
- Single crate: Everything lives in one crate (like mtp-rs). Keeps things simple, avoids cross-crate dependency management.
- Hand-rolled pack/unpack: We serialize SMB messages manually with
ReadCursor/WriteCursorinstead of using derive macros. Full control, easier to debug protocol issues, and the wire format has too many variable-length fields and padding rules for serde to handle well. dyn Transport: The transport layer uses trait objects (async_trait) instead of generics. Simpler API, and the overhead is negligible compared to network I/O.- Pipeline as a core feature: The pipeline isn't an optimization bolted on later. It's the reason this library exists. The credit window, message sequencing, and compounding are all designed around it.
- Runtime-agnostic: We don't depend on tokio directly. Use
futurestraits. Tokio is a dev-dependency for running async tests.
- Testing with real SMB servers (Windows, Samba, NAS devices) and reporting results
- Bug reports with reproduction steps
- Protocol edge cases (compound failures, credit management, etc.)
- Doc improvements
- Server implementation (this is a client library)
- QUIC or RDMA transport
- Kerberos authentication (planned but not yet)
- SMB1 support (deprecated, insecure)
These might come later, but they're not the current focus.
If you need to understand SMB2/3, the spec files in docs/specs/ are the primary reference. The implementation plan at docs/specs/implementation-plan.md has a good overview of the protocol flow and known pitfalls.
The protocol is essentially:
- Negotiate capabilities (dialect, signing, encryption)
- Authenticate (NTLM challenge/response)
- Connect to a share (tree connect)
- Open files, read/write/list, close files
- Disconnect
Everything is little-endian on the wire (except the TCP transport framing, which is big-endian). Strings are UTF-16LE.
- Fork and create a branch
- Make your changes
- Run
just(checks format, lint, test, and doc) - Run
just msrvto verify Rust 1.85 compatibility - If you have a Samba server, run integration tests
- Open a PR with a clear description including how you tested your changes
For non-trivial changes, consider opening an issue first to discuss the approach.
Open an issue. Happy to chat!