Compare commits

...

10 Commits

Author SHA1 Message Date
izackp 4c50eed0b4 docs: add CLAUDE.md
ci / build (auto, macos-latest) (push) Has been cancelled
ci / build (auto, ubuntu-22.04) (push) Has been cancelled
ci / build (auto, ubuntu-24.04) (push) Has been cancelled
ci / build (nettle, ubuntu-22.04) (push) Has been cancelled
2026-06-04 21:58:22 -04:00
Mike Frysinger b5775df441 prng: support getrandom & getentropy
If the C library supports these random functions, use them directly
instead of reading the /dev/urandom file.  This makes life easier on
platforms that don't have /dev/urandom (like WASM).
2026-02-27 19:55:52 -05:00
Mike Frysinger 8e472066be select: use SA_RESTART with signals
Rely on the OS to automatically restart syscalls that were interrupted
by signals.  This makes code overall more robust because we don't have
to explicitly handle EINTR everywhere ourselves.
2026-02-27 17:07:56 -05:00
Mike Frysinger 3f91cce5ff client: drop NACL check
Since Chrome has completely dropped NaCl support now on all platforms,
there's no sense in continuing to support it in mosh.
2026-02-27 17:04:59 -05:00
Alex Chernyakhovsky 5f5d35c7a8 Run apt update before apt install 2026-02-27 16:44:02 -05:00
Mike Frysinger b245486d9c gitignore: add config.cache
This is generated when running `./configure -C`.
2026-02-27 16:39:59 -05:00
Eric Dorland ee757a2210 Fix compile failure on MacOS X
std::shared_ptr::unique() is deprecated in C++17 and removed in C++20.

Inspired by PR#1362.

Snippet of the failure:

```
In file included from ../../src/terminal/terminal.h:42:
../../src/terminal/terminalframebuffer.h:431:23: error: 'unique' is deprecated [-Werror,-Wdeprecated-declarations]
  431 |     if ( !mutable_row.unique() ) {
      |                       ^
/Applications/Xcode_16.4.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/__memory/shared_ptr.h:752:3: note: 'unique' has been explicitly marked deprecated here
  752 |   _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI bool unique() const _NOEXCEPT { return use_count() == 1; }
      |   ^
/Applications/Xcode_16.4.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:731:41: note: expanded from macro '_LIBCPP_DEPRECATED_IN_CXX17'
  731 | #    define _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_DEPRECATED
      |                                         ^
/Applications/Xcode_16.4.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/__config:696:49: note: expanded from macro '_LIBCPP_DEPRECATED'
  696 | #      define _LIBCPP_DEPRECATED __attribute__((__deprecated__))
      |                                                 ^
1 error generated.
```
2026-02-27 16:38:09 -05:00
Eric Dorland 64ce9aad9a Drop the -pedantic flag from CXX_FLAGS
Abseil uses certain compiler extensions intentionally (see abseil/abseil-cpp#157) so it triggers multiple warnings enabled by -pedantic (-Wnullability-extension, -Wgcc-compat, -Wvariadic-macro-arguments-omitted at a minimum) as seen in #1373.
2026-02-27 16:38:09 -05:00
Alex Chernyakhovsky 59e3aa96c7 Upgrade ubuntu runners (+2y) 2026-02-23 17:42:45 -05:00
Benjamin Barenblat f7b350f0a8 Remove Benjamin Barenblat from Debian uploaders 2026-01-19 19:39:46 -05:00
11 changed files with 148 additions and 16 deletions
+3 -3
View File
@@ -8,11 +8,11 @@ jobs:
strategy:
matrix:
os: [macos-latest, ubuntu-20.04, ubuntu-22.04]
os: [macos-latest, ubuntu-22.04, ubuntu-24.04]
crypto: [auto]
include:
- crypto: nettle
os: ubuntu-20.04
os: ubuntu-22.04
steps:
@@ -20,7 +20,7 @@ jobs:
- name: "setup linux build environment"
if: ${{ startsWith(matrix.os, 'ubuntu') }}
run: sudo apt install -y protobuf-compiler libprotobuf-dev libutempter-dev autoconf automake nettle-dev
run: sudo apt update && sudo apt install -y protobuf-compiler libprotobuf-dev libutempter-dev autoconf automake nettle-dev
- name: "setup macos build environment"
if: ${{ startsWith(matrix.os, 'macos') }}
+1 -1
View File
@@ -59,7 +59,7 @@ jobs:
- name: "setup linux build environment"
if: ${{ startsWith(matrix.os, 'ubuntu') }}
run: sudo apt install -y protobuf-compiler libprotobuf-dev libutempter-dev autoconf automake nettle-dev
run: sudo apt update && sudo apt install -y protobuf-compiler libprotobuf-dev libutempter-dev autoconf automake nettle-dev
- name: "Install gtar wrapper"
if: ${{ startsWith(matrix.os, 'macos') }}
+1
View File
@@ -25,6 +25,7 @@ aminclude_static.am
src/include/config.h
src/include/config.h.in
src/include/config.h.in~
/config.cache
/config.log
/config.status
/configure
+86
View File
@@ -0,0 +1,86 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What is Mosh
Mosh (mobile shell) is a remote terminal application that supports intermittent connectivity and roaming. Unlike SSH, it uses UDP and synchronizes terminal state as diffs, allowing the client to do predictive local echo and survive network changes.
## Build System
Mosh uses GNU Autotools (Autoconf/Automake).
```bash
./autogen.sh # Generate build scripts (required after cloning)
./configure # Configure build
make # Build
make check # Run all tests
```
Useful configure options:
- `--enable-compile-warnings=error` — treat warnings as errors
- `--enable-asan` — enable AddressSanitizer
- `--enable-code-coverage` — enable coverage reporting
- `--with-crypto-library=openssl|nettle|apple-common-crypto` — choose crypto backend (default: autodetect)
- `--disable-client` / `--disable-server` — build only one side
## Running Tests
```bash
make check # Run all tests
make V=1 check # Verbose output
make check-code-coverage # Coverage report (requires --enable-code-coverage)
```
Test types:
- **Unit tests** (`src/tests/`): ocb-aes, encrypt-decrypt, base64, nonce-incr, is-utf8-locale
- **End-to-end tests**: tmux-based display/network/unicode/resize tests (see `src/tests/README.md`)
## Static Analysis / Linting
```bash
make cppcheck # cppcheck static analysis
make scan-build # Clang static analyzer
```
Code style uses `.clang-format` (Mozilla-based, 116-column limit). CI enforces clang-format on PRs.
## Dependencies
Ubuntu/Debian:
```bash
sudo apt install build-essential protobuf-compiler libprotobuf-dev pkg-config \
libutempter-dev zlib1g-dev libncurses5-dev libssl-dev bash-completion tmux less
```
## Architecture
```
src/
frontend/ — mosh-client.cc, mosh-server.cc entry points
crypto/ — AES-OCB encryption; supports OpenSSL, Nettle, Apple Common Crypto
network/ — UDP transport, state sync, compression, fragmentation
terminal/ — Terminal emulator, Unicode, character cell rendering
statesync/ — State diff/sync logic between client and server
protobufs/ — Protobuf definitions (hostinput, userinput, transportinstruction)
util/ — PTY, locale, timestamps, select wrapper
tests/ — Unit + end-to-end tests
fuzz/ — Fuzzing targets
```
**Data flow:**
1. `mosh-client` SSHes to server, spawns `mosh-server`
2. Server sends AES-128 key + UDP port over SSH, then SSH closes
3. Client and server exchange terminal state diffs over UDP
4. Client applies predictive local echo using its own terminal emulator
5. Server sends authoritative state; client reconciles
**Crypto:** AES-128-OCB with a fresh key per session. Key is passed out-of-band via SSH. The crypto backend is selected at configure time; the abstraction lives in `src/crypto/`.
**State sync:** Both ends maintain a `Terminal::Complete` object. The network layer (`src/network/`) sends `TransportInstruction` protobufs containing diffs. The client uses `src/statesync/` to apply them.
## Security Notes (from README)
- Hardening flags enabled by default (`-fstack-protector-all`, `-D_FORTIFY_SOURCE=2`, `-fPIE`, RELRO, etc.)
- `mosh-server` must ensure process environment is not readable by other users before writing the session key to stdout
- C++17 is required minimum (protobuf compatibility)
+6 -3
View File
@@ -40,7 +40,7 @@ AC_ARG_ENABLE([compile-warnings],
;;
maximum)
WARNING_CXXFLAGS="-Wall"
PICKY_CXXFLAGS="-Wextra -pedantic -Wno-long-long -Weffc++ -Wmissing-declarations"
PICKY_CXXFLAGS="-Wextra -Wno-long-long -Weffc++ -Wmissing-declarations"
;;
error)
# remove -Wno-c++17-extensions once protocolbuffers/protobuf#9181 is
@@ -48,11 +48,11 @@ AC_ARG_ENABLE([compile-warnings],
# remove -Wno-unused-parameter once
# protocolbuffers/protobuf#10357 is resolved
WARNING_CXXFLAGS="-Wall -Werror -Wno-c++17-extensions"
PICKY_CXXFLAGS="-Wextra -pedantic -Wno-long-long -Weffc++ -Wmissing-declarations -Wno-unused-parameter"
PICKY_CXXFLAGS="-Wextra -Wno-long-long -Weffc++ -Wmissing-declarations -Wno-unused-parameter"
;;
distcheck)
WARNING_CXXFLAGS="-Wall -Werror"
PICKY_CXXFLAGS="-Wextra -pedantic -Wno-long-long -Weffc++ -Wmissing-declarations"
PICKY_CXXFLAGS="-Wextra -Wno-long-long -Weffc++ -Wmissing-declarations"
AX_CHECK_COMPILE_FLAG([-Wno-error=unused-parameter],
[PICKY_CXXFLAGS="$PICKY_CXXFLAGS -Wno-error=unused-parameter"], [], [-Werror])
AX_CHECK_COMPILE_FLAG([-Wno-error=c++11-extensions],
@@ -272,6 +272,7 @@ AC_CHECK_HEADERS(m4_normalize([
stdlib.h
string.h
sys/ioctl.h
sys/random.h
sys/resource.h
sys/socket.h
sys/stat.h
@@ -304,6 +305,8 @@ AC_TYPE_UINTPTR_T
# Checks for library functions.
AC_CHECK_FUNCS(m4_normalize([
getentropy
getrandom
gettimeofday
posix_memalign
cfmakeraw
+6
View File
@@ -1,3 +1,9 @@
mosh (1.4.0-2) UNRELEASED; urgency=medium
* Remove Benjamin Barenblat from Uploaders.
-- Benjamin Barenblat <bbaren@debian.org> Mon, 19 Jan 2026 19:38:42 -0500
mosh (1.4.0-1) unstable; urgency=medium
* New upstream release.
+1 -1
View File
@@ -2,7 +2,7 @@ Source: mosh
Section: net
Priority: optional
Maintainer: Keith Winstein <keithw@mit.edu>
Uploaders: Alex Chernyakhovsky <achernya@debian.org>, Benjamin Barenblat <bbaren@debian.org>
Uploaders: Alex Chernyakhovsky <achernya@debian.org>
Build-Depends: debhelper-compat (= 12), protobuf-compiler, libprotobuf-dev, pkg-config, libutempter-dev, zlib1g-dev, libncurses5-dev, libssl-dev, bash-completion, locales <!nocheck>, tmux <!nocheck>, less <!nocheck>
Rules-Requires-Root: binary-targets
Standards-Version: 4.6.1
+40 -1
View File
@@ -33,6 +33,20 @@
#ifndef PRNG_HPP
#define PRNG_HPP
#include "config.h"
#if !defined( HAVE_GETENTROPY ) && !defined( HAVE_GETRANDOM )
#define HAVE_URANDOM 1
#else
#undef HAVE_URANDOM
#endif
#include <unistd.h>
#ifdef HAVE_SYS_RANDOM_H
#include <sys/random.h>
#endif
#include <algorithm>
#include <cstdint>
#include <fstream>
#include <string>
@@ -43,21 +57,29 @@
We rely on stdio buffering for efficiency. */
#ifdef HAVE_URANDOM
static const char rdev[] = "/dev/urandom";
#endif
using namespace Crypto;
class PRNG
{
private:
#ifdef HAVE_URANDOM
std::ifstream randfile;
#endif
/* unimplemented to satisfy -Weffc++ */
PRNG( const PRNG& );
PRNG& operator=( const PRNG& );
public:
PRNG() : randfile( rdev, std::ifstream::in | std::ifstream::binary ) {}
PRNG()
#ifdef HAVE_URANDOM
: randfile( rdev, std::ifstream::in | std::ifstream::binary )
#endif
{}
void fill( void* dest, size_t size )
{
@@ -65,10 +87,27 @@ public:
return;
}
#if defined( HAVE_GETRANDOM )
if ( getrandom( dest, size, 0 ) != static_cast<ssize_t>( size ) ) {
throw CryptoException( "getrandom fell short" );
}
#elif defined( HAVE_GETENTROPY )
// getentropy() can only read up to 256 bytes at a time :(.
const size_t max_read = 256;
while ( size ) {
size_t this_size = std::min( max_read, size );
if ( getentropy( dest, this_size ) ) {
throw CryptoException( "getentropy fell short" );
}
size -= this_size;
dest = static_cast<char*>( dest ) + this_size;
}
#else
randfile.read( static_cast<char*>( dest ), size );
if ( !randfile ) {
throw CryptoException( "Could not read from " + std::string( rdev ) );
}
#endif
}
uint8_t uint8()
-4
View File
@@ -105,11 +105,7 @@ static void print_colorcount( void )
printf( "%d\n", color_val );
}
#ifdef NACL
int mosh_main( int argc, char* argv[] )
#else
int main( int argc, char* argv[] )
#endif
{
unsigned int verbose = 0;
/* For security, make sure we don't dump core */
+3 -2
View File
@@ -427,8 +427,9 @@ public:
if ( row == -1 )
row = ds.get_cursor_row();
row_pointer& mutable_row = rows.at( row );
// If the row is shared, copy it.
if ( !mutable_row.unique() ) {
// If the row is shared, copy it. This is only safe because mosh isn't
// multi-threaded.
if ( mutable_row.use_count() > 1 ) {
mutable_row = std::make_shared<Row>( *mutable_row );
}
return mutable_row.get();
+1 -1
View File
@@ -108,7 +108,7 @@ public:
/* Register a handler, which will only be called when pselect()
is interrupted by a (possibly queued) signal. */
struct sigaction sa;
sa.sa_flags = 0;
sa.sa_flags = SA_RESTART;
sa.sa_handler = &handle_signal;
fatal_assert( 0 == sigfillset( &sa.sa_mask ) );
fatal_assert( 0 == sigaction( signum, &sa, NULL ) );