proxy

package
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 5, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package proxy wires an inbound (user) channel to an outbound (target) channel and shuttles data and requests between them.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrAccessDenied: kimlik ya da yetki reddi — bir arıza DEĞİL,
	// güvenlik olayı. Çağıran bunu istemciye "access denied" olarak
	// yansıtır (SSH reject sebebi / HTTP 403).
	ErrAccessDenied = errors.New("proxy: access denied")

	// ErrIdleTimeout / ErrMaxLifetime: oturumu KAPATAN sınırlar.
	// Hata olarak çağırana dönmezler — context.Cause ile okunup denetim
	// kaydına yazılırlar (bkz. idle.go).
	ErrIdleTimeout = errors.New("proxy: session idle timeout")
	ErrMaxLifetime = errors.New("proxy: session max lifetime")

	// ErrRecordingFailed: kayıt yazımı oturum ortasında bozuldu.
	// Oturum KAPATILIR — kayıtsız oturum yok.
	ErrRecordingFailed = errors.New("proxy: recording failed")

	// ErrUnavailable: hedefe ulaşılamadı, kayıt açılamadı, veritabanı
	// erişilemiyor. Kullanıcının suçu değil; birinin müdahale etmesi
	// gerekir. Çağıran "connection failed" / HTTP 503 der.
	ErrUnavailable = errors.New("proxy: session unavailable")
)
View Source
var ErrDirectoryRefused = errors.New("proxy: the directory no longer vouches for this user")

* ErrDirectoryRefused, kimlik kaynağının bu kullanıcı için oturumu * reddettiği: dizinde YOK ya da hesap KAPATILMIŞ. * * Arızadan ayrı bir hata olması şart. "Cevap veremedim" ile "bu kişi * artık burada değil" aynı yola düşerse, bir dizin kesintisi ya herkesi * dışarıda bırakır ya da kapatılmış hesapları içeri alır — hangi tarafa * eğdiğimize bakmaksızın yanlış.

View Source
var ErrShortPayload = errors.New("proxy: request payload too short")

ErrShortPayload, payload beklenen alanları taşımayacak kadar kısaysa döner.

View Source
var ErrShuttingDown = errors.New("proxy: the bastion is shutting down")

* ErrShuttingDown: bastion kapanıyor ve bekleme süresi doldu. * * ⚠️ ErrTerminated'DAN AYRI TUTULUYOR. İkisi de oturumu kapatıyor ama * denetim kaydına ve kullanıcıya bambaşka şeyler söylüyorlar: biri "bir * yönetici seni kesti", öbürü "makine yeniden başlıyor". Aynı sebebi * kullansaydık, bir dağıtım gecesi denetim defteri kimsenin yapmadığı * yüzlerce kesme ile dolardı.

View Source
var ErrTerminated = errors.New("proxy: session terminated by an administrator")

ErrTerminated: oturumu bir yönetici kesti. bound()'un ürettiği ErrIdleTimeout / ErrMaxLifetime ile aynı raftadır: Run bunu context.Cause'dan okuyup denetim satırına "closed_by" olarak yazıyor.

Functions

func TerminatedBy

func TerminatedBy(cause error) (string, bool)

* TerminatedBy, kesme sebebinden KİMİN kestiğini çıkarır. * * ⚠️ errors.As, metin bölme DEĞİL. Aktör tipli hatanın alanında * duruyor; sebebi Error() metninden geri kazımak, içinde ": " geçen bir * adı sessizce kırpardı.

Types

type Broker

type Broker struct {
	// contains filtered or unexported fields
}

Broker, bir kullanıcı kanalı (down) ile bir hedef kanalı (up) arasında veriyi ve request'leri iki yönde taşır.

func New

func New(down ssh.Channel, downR <-chan *ssh.Request, up ssh.Channel, upR <-chan *ssh.Request, rec *record.Writer, recordInput bool, policy RequestPolicy, logger *slog.Logger) *Broker

New wires an inbound channel to an outbound one.

rec nil geçilebilir (kayıt kapalı). recordInput yalnızca config açıkça istediğinde true olmalı.

func (*Broker) Run

func (b *Broker) Run(ctx context.Context) error

Run shuttles data and requests until the session ends, then returns.

func (*Broker) WithSFTP

func (b *Broker) WithSFTP(sink SFTPSink) *Broker

WithSFTP, SFTP denetim hedefini bağlar.

Ayrı bir kurucu yerine ayarlayıcı olması bilinçli: SFTP kapalıyken (varsayılan) çağıranların hiçbiri değişmiyor.

type Deps

type Deps struct {
	Store   *store.Store
	Records *record.Store
	/*
	 * RecordMinFree, altına inildiğinde YENİ oturumun reddedildiği boş
	 * alan. 0 kapalı. Gerekçesi Open'daki kullanım yerinde.
	 */
	RecordMinFree uint64
	Authority     *ca.CA
	Logger        *slog.Logger
	RecordInput   bool

	// Requests, oturum kanalı request'lerinin süzgeci (requests.go).
	// Sıfır değeri kullanılabilir: env whitelist'i varsayılana düşer,
	// tip listeleri zaten sabit.
	Requests RequestPolicy

	// IdleTimeout, iki yönde de bayt akmayan oturumun kapatılma süresi.
	// 0 = kapalı (bkz. config.SessionConfig.IdleTimeout).
	IdleTimeout time.Duration

	// MaxLifetime, oturumun mutlak ömrü. 0 = kapalı.
	MaxLifetime time.Duration

	// Probe, hedefte KOMUT ÇALIŞTIRARAK tanıma. Sıfır değeri KAPALI —
	// yani hiçbir şey çağırmadıkça postern hedefte kullanıcının oturumu
	// dışında bir şey çalıştırmaz.
	Probe ProbePolicy

	/*
	 * FreshenRoles, oturum AÇILIRKEN kullanıcının rollerini aktif kimlik
	 * kaynağından tazeler. nil ise tazeleme yapılmaz.
	 *
	 * ⚠️ NEDEN BURADA: iki kapı (SSH kanalı ve web terminali) tek
	 * fonksiyondan geçiyor, yani kural ikisine birden uygulanıyor —
	 * "iki kapı, tek gerçek". Kimlik doğrulama geri çağrısında değil,
	 * çünkü orası el sıkışmanın içi: bir handshake'te birden çok kez
	 * çağrılıyor ve orada ağ isteği yapmak, kimliği doğrulanmamış bir
	 * bağlantıyı dizine karşı bir yükseltici hâline getirirdi.
	 *
	 * ErrDirectoryRefused dönerse oturum REDDEDİLİR; başka bir hata
	 * yalnızca loglanır ve saklanan rollerle devam edilir (dizin arızası
	 * yetki yokluğu değildir).
	 */
	FreshenRoles func(ctx context.Context, username string) error

	// Events, canlı izleme akışı. nil ise olay yayınlanmaz.
	//
	// ⚠️ Publish BLOKLAMAZ (bkz. events.Bus): burası bir oturumun açılış
	// ve kapanış yolu ve izleyen bir panel, izlediği oturumu
	// bekletemez.
	Events events.Publisher

	// Live, akan oturumların defteri: yöneticinin kesme düğmesi buradan
	// çalışıyor. nil olabilir — o zaman kayıt tutulmuyor ve hiçbir
	// oturum kesilemiyor (Live'ın bütün metotları nil-güvenli).
	Live *Live
}

Deps, oturum açmak için gereken altyapı. Hem sshd.Server hem httpapi.Server bunu kurar.

type ExecRequest

type ExecRequest struct {
	Command string
}

ExecRequest, "exec" payload'ı (RFC 4254 §6.5).

func ParseExec

func ParseExec(payload []byte) (ExecRequest, error)

ParseExec parses an "exec" payload.

type Live

type Live struct {
	// contains filtered or unexported fields
}

Live, akan oturumların id -> iptal eşlemesi.

func NewLive

func NewLive() *Live

NewLive, boş bir defter kurar.

func (*Live) Running

func (l *Live) Running(id string) bool

Running, oturumun bu süreçte akıp akmadığını söyler.

func (*Live) RunningIDs

func (l *Live) RunningIDs() map[string]bool

RunningIDs, bu süreçte akan oturumların kimlikleri.

Panel, veritabanındaki "açık" satırları bununla süzüyor: açık ama akmayan satır, çökmeden kalmış bir izdir ve "çalışıyor" diye gösterilmemeli.

func (*Live) Terminate

func (l *Live) Terminate(id, by string) bool

* Terminate, oturumu keser ve KESTİĞİNİ bildirir. * * Dönen false "böyle akan bir oturum yok" demek — çağıran bunu * "kesildi" diye çevirmemeli. Bu ayrım, bu dosyanın var olma sebebi. * * ⚠️ SEBEP KİMİ İÇERİYOR. context.Cause zincirinden okunan metin * doğrudan denetim satırına ve kullanıcıya giden cümleye dönüşüyor; * "kesildi" ile "yönetici admin kesti" arasındaki fark, olay sonrası * kaydı okuyan için işin tamamı. errors.Is(ErrTerminated) yine * çalışıyor, çünkü sarmalıyoruz.

func (*Live) TerminateAll

func (l *Live) TerminateAll(cause error) int

* TerminateAll, akan bütün oturumları verilen sebeple keser ve kaç * tanesini kestiğini döner. * * ⚠️ KAPANIŞIN SON ADIMI. Bekleme süresi dolduğunda çağrılıyor: * oturumları öylece bırakıp süreçten çıkmak, kaydı yarım ve arşiv * kuyruğuna hiç girmemiş hâlde bırakmak demekti. Buradan geçen her * oturum normal kapanış yolunu yürüyor — kullanıcı sebebini görüyor, * kayıt kapanıyor, Close arşivi kuyruğa yazıyor. * * ⚠️ KOPYA ÜZERİNDE GEZİLİYOR. cancel çağrıları Run'ın kendi * goroutine'lerini uyandırıyor ve onlar remove'a giriyor; defterin * kilidini tutarken iptal etmek kilitlenme demekti (Terminate'teki * notun aynısı).

type ProbePolicy

type ProbePolicy struct {
	Enabled bool
	Refresh time.Duration
	Timeout time.Duration
}

* ProbePolicy, tanımanın açık olup olmadığı ve sınırları. * * Sıfır değeri KAPALI ve bu kasıtlı: yapıyı sıfır değeriyle kuran her * çağıran (testler dahil) hedefe dokunmayan davranışı alır.

type PtyRequest

type PtyRequest struct {
	Term          string
	Columns, Rows uint32
	Width, Height uint32 // piksel cinsinden; genelde 0
	Modes         string // opaque terminal modes — parse etme, olduğu gibi ilet (Ek C.4)
}

PtyRequest, "pty-req" payload'ı (RFC 4254 §6.2).

func ParsePty

func ParsePty(payload []byte) (PtyRequest, error)

ParsePty parses a "pty-req" payload.

type Request

type Request struct {
	// Username, DOĞRULANMIŞ postern kullanıcı adıdır — istemcinin iddia
	// ettiği değil. SSH tarafında Permissions'tan, web tarafında oturum
	// kaydından gelir; ikisi de kimliği kendi kapısında doğrulamış olur.
	Username string

	/*
	 * AccountID, bağlantının bağlı olduğu users.id.
	 *
	 * ⚠️ AD DEĞİL KİMLİK, VE BOŞ GEÇİLEMİYOR. Ad yeniden
	 * kullanılabiliyor (purge onu serbest bırakıyor), kimlik kalıcı.
	 * Bunu kapıda çözüp buraya taşımak, kanal açılırken "bu bağlantı
	 * HÂLÂ o kişiye mi ait" sorusunun sorulabilmesinin tek yolu.
	 */
	AccountID string

	TargetName string
	SrcIP      string
}

Request, açılacak oturumun kim/nereye bilgisi.

type RequestPolicy

type RequestPolicy struct {
	// AcceptEnv, geçmesine izin verilen ortam değişkeni adları.
	// Sondaki * joker: "LC_*" tüm LC_ ile başlayanları kapsar.
	//
	// nil = varsayılan (defaultAcceptEnv). BOŞ DİLİM = hiçbiri; ikisi
	// farklı şeyler ve YAML bu ikisini ayırt edebiliyor.
	AcceptEnv []string

	/*
	 * AllowSFTP, `subsystem sftp` kanalını açar.
	 *
	 * ⚠️ VARSAYILAN KAPALI ve öyle kalmalı. Açık geldiğinde, yükseltme
	 * yapan bir operatör hiçbir şey yapmadan yeni bir veri çıkış yolu
	 * kazanmış olurdu — üstelik farkında olmadan.
	 *
	 * Açıkken bile SFTP yalnızca dosya olayları denetlenerek geçiyor
	 * (sftp.go). Denetim kurulamıyorsa kanal AÇILMIYOR: bu bayrağın
	 * anlamı "sftp serbest" değil, "denetimli sftp serbest".
	 */
	AllowSFTP bool
}

RequestPolicy, oturum kanalı request'lerinin geçiş kuralları.

type SFTPSink

type SFTPSink interface {
	Emit(sftpaudit.Event)
}

SFTPSink, üretilen dosya olaylarının gideceği yer.

Emit veri yolundan çağrılıyor: yavaş olmamalı. Kalıcılaştırma (veritabanına yazım) çağıranın işi.

type Session

type Session struct {
	// ID, denetim satırının ve .cast dosyasının ortak anahtarı.
	ID string

	// OSUser, policy'nin verdiği karar — çağıran log'a yazsın diye açık.
	OSUser string

	// Log, oturumun alanları bağlanmış logger'ı (user, target, session_id,
	// record_path). Çağıran kendi olaylarını bununla yazsın ki satırlar
	// aynı oturumda birleşsin.
	Log *slog.Logger
	// contains filtered or unexported fields
}

Session, açılmış ama henüz sürülmemiş bir oturum: hedefe bağlanılmış, kayıt dosyası açılmış, denetim satırı yazılmıştır. Run ile sürülür, Close ile kapatılır.

func Open

func Open(ctx context.Context, deps Deps, req Request) (*Session, error)

Open, yetkiyi denetler ve oturumu hedefe kadar kurar.

Hata döndüğünde HİÇBİR ŞEY açık kalmaz: kısmi kurulum kendi içinde temizlenir ve dönen Session nil'dir — çağıranın Close çağırmasına gerek yoktur.

func (*Session) Close

func (s *Session) Close(ctx context.Context)

Close, oturumu kapatır: kayıt dosyası, denetim satırı, hedef bağlantısı. İkinci çağrı no-op — çağıran defer'la koyabilsin diye.

func (*Session) Run

func (s *Session) Run(ctx context.Context, down ssh.Channel, downR <-chan *ssh.Request) error

Run, istemci kanalını hedefe bağlar ve oturum bitene kadar sürer.

down/downR istemci tarafı: SSH'ta kabul edilmiş ssh.Channel, web'de WebSocket'i ssh.Channel gibi giydiren adaptör. Broker ikisini ayırt etmez — arayüz sözleşmesinin bütün faydası bu.

type WindowChangeRequest

type WindowChangeRequest struct {
	Columns, Rows uint32
	Width, Height uint32
}

WindowChangeRequest, "window-change" payload'ı (RFC 4254 §6.7).

func ParseWindowChange

func ParseWindowChange(payload []byte) (WindowChangeRequest, error)

ParseWindowChange parses a "window-change" payload.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL