Documentation
¶
Index ¶
- Constants
- func StatusPacket(id uint32, code uint32, msg string) []byte
- type Decider
- type Denial
- type Event
- type Op
- type Request
- type Session
- func (s *Session) Finish()
- func (s *Session) FromClient(p []byte) error
- func (s *Session) FromClientTo(p []byte, forward func([]byte) error) error
- func (s *Session) FromTarget(p []byte) error
- func (s *Session) SetPolicy(d Decider)
- func (s *Session) SetReadOnly(on bool)
- func (s *Session) TakeDenials() []Denial
- func (s *Session) TargetAtBoundary() bool
Constants ¶
const ( // StatusPermissionDenied, politikanın reddettiği istek için. // // ⚠️ FAILURE (4) DEĞİL. İstemciler bu ikisine farklı tepki veriyor: // sftp/scp PERMISSION_DENIED'ı "bu yol sana kapalı" diye gösterip // devam ediyor, FAILURE ise çoğu istemcide "sunucu arızası" gibi // okunuyor. Reddin kullanıcıya DOĞRU görünmesi, reddin kendisi kadar // önemli: yanlış kod, yöneticiye açılmış bir arıza kaydı demek. StatusPermissionDenied uint32 = 3 /* * StatusOpUnsupported, TANIMADIĞIMIZ bir işlem için. * * ⚠️ REDDİN SEBEBİ DOĞRU SÖYLENMELİ. Tanımadığımız bir uzantıya * "bu yola iznin yok" demek yalan: sorun yol değil, postern'in o fiili * modellememesi. Taslak (draft-ietf-secsh-filexfer-02 §8) tanınmayan * extended-request için bu kodu ŞART koşuyor. * * Pratik faydası da var: istemciler bu kodu görünce standart işlemlere * geri düşüyor — yani postern'in DENETLEYEBİLDİĞİ fiillere. 3 dönseydik * istemci yolu suçlar, geri düşmez ve kullanıcı neden çalışmadığını * anlamazdı. */ StatusOpUnsupported uint32 = 8 )
Variables ¶
This section is empty.
Functions ¶
func StatusPacket ¶ added in v1.2.0
* StatusPacket, tek bir SSH_FXP_STATUS paketini tel biçiminde üretir. * * Biçim (v3): * * uint32 uzunluk (tip baytından itibaren, kendisi hariç) * byte 101 SSH_FXP_STATUS * uint32 istek kimliği * uint32 durum kodu * string mesaj UTF-8 * string dil etiketi * * ⚠️ İSTEK KİMLİĞİ REDDEDİLEN İSTEĞİNKİYLE AYNI OLMALI. İstemci * cevapları kimliğe göre eşliyor; başka bir kimlikle cevap vermek, o * isteği sonsuza kadar cevapsız bırakır — yani reddetmek yerine * istemciyi askıda bırakmış oluruz. * * ⚠️ DİL ETİKETİ BOŞ. RFC boş bırakmaya izin veriyor ve istemciler * yok sayıyor; uydurma bir etiket ("en") göndermek, mesajın gerçekten * o dilde olduğu iddiası olurdu.
Types ¶
type Decider ¶ added in v1.2.0
* Decider, bir isteğe izin verilip verilmediğini söyler. * * ⚠️ BLOKLAMAMALI. Session'ın tek muteksi altında, veri yolunun üstünde * çalışıyor; burada geçen her milisaniye hedef→istemci akışını da * durduruyor (bkz. frame.go, decide). * * reason, hem istemciye giden STATUS mesajına hem de denetim satırına * giriyor: kullanıcı neden reddedildiğini görmeli, operatör de.
type Denial ¶ added in v1.2.0
type Denial struct {
// Status, SFTP veri akışına yazılacak cevap paketi.
Status []byte
// Notice, stderr'e yazılacak insan satırı.
Notice string
}
* Denial, reddedilen bir isteğe verilecek iki cevap. * * ⚠️ İKİSİ AYRI KANALDAN GİDİYOR ve ikisi de gerekli. Status, SFTP veri * akışında istemcinin PROTOKOL cevabı: onsuz istek kimliği açık kalır ve * istemci sonsuza kadar bekler. Notice ise İNSANA giden satır, stderr'den. * * ⚠️ NEDEN İNSAN SATIRI DA ŞART: OpenSSH'in sftp istemcisi STATUS'un * mesaj alanını hiç okumuyor (get_status yalnızca tip, kimlik ve kodu * ayrıştırıp tamponu bırakıyor) ve `get`/`ls` öncesi yaptığı stat * başarısız olunca "not found" yazıyor — durum kodundan bağımsız olarak. * Yani reddi UYGULUYORUZ, defterine YAZIYORUZ, ama kullanıcı * "engellendim" ile "dosya yok"u ayırt edemiyor. Ölçüldü.
type Event ¶
type Event struct {
At time.Time `json:"at"`
Op Op `json:"op"`
Path string `json:"path"`
// NewPath yalnızca rename ve symlink'te dolu.
NewPath string `json:"new_path,omitempty"`
// Flags yalnızca open/transfer'da dolu ("read", "write,creat,trunc").
Flags string `json:"flags,omitempty"`
// Read/Wrote, transfer olayında GERÇEKTEN taşınan bayt.
Read int64 `json:"read,omitempty"`
Wrote int64 `json:"wrote,omitempty"`
// OK, hedefin işlemi kabul edip etmediği.
OK bool `json:"ok"`
Status uint32 `json:"status,omitempty"`
Detail string `json:"detail,omitempty"`
/*
* Folded, bu satırın kaç AYRI reddi temsil ettiği — yalnızca
* katlanmış retlerin özet satırında dolu (flushDenyRunLocked).
*
* ⚠️ SAYIYI PROZDAN OKUMAK ZORUNDA KALMAMAK İÇİN VAR. Sayı zaten
* Detail'de bir cümlenin içinde duruyordu ("… (%d further identical
* refusals)") ve oradan okumanın tek yolu İngilizce ayrıştırmak.
* ÖLÇÜLDÜ: sayıyı olayları sayarak bulan bir tüketici, 32 KiB'lık
* parçalar hâlinde on bin kez reddedilen bir oturumu "2 ret" diye
* raporluyordu — yani en ısrarlı oturum en küçük sayıyı taşıyordu.
*
* ⚠️ ÖZET SATIRININ KENDİSİ BİR RET DEĞİL. Bir dizinin ilk reddi
* kendi satırını yazıyor; Folded yalnızca ONDAN SONRAKİLERİ sayıyor.
* İkisini toplayan tüketici doğru sayıyı buluyor (bkz. sftpJournal).
*/
Folded int `json:"folded,omitempty"`
}
Event, denetim kaydına düşen tek satır.
type Op ¶
type Op string
Op, denetim olayının cinsi.
const ( OpOpen Op = "open" OpTransfer Op = "transfer" OpRemove Op = "remove" OpRename Op = "rename" OpMkdir Op = "mkdir" OpRmdir Op = "rmdir" OpSetstat Op = "setstat" OpSymlink Op = "symlink" OpOpendir Op = "opendir" OpLink Op = "hardlink" OpExtended Op = "extended" // OpUnknown, TANIMADIĞIMIZ bir istek türü. OpUnknown Op = "unknown" // Aşağıdakiler yalnızca REDDEDİLDİKLERİNDE satır üretiyor: izin verilen // üstveri istekleri sessiz kalıyor. Kararın verildiği tek yer // onRequest'in switch'i — orada listelenmeyen tip bekleyenler // tablosuna girmiyor, dolayısıyla satır da üretmiyor. OpStat Op = "stat" OpReaddir Op = "readdir" OpRealpath Op = "realpath" OpReadlink Op = "readlink" )
type Request ¶ added in v1.2.0
type Request struct {
// Op, isteğin denetimdeki adı.
Op Op
// Path, normalleştirilmiş yol.
Path string
// NewPath, ikinci yol (rename, symlink, link); yoksa boş.
NewPath string
// Write, isteğin ad uzayını ya da içeriği DEĞİŞTİRME amacı taşıdığı.
Write bool
}
* Request, politikaya sunulan istek. * * ⚠️ YOLLAR NORMALLEŞTİRİLMİŞ GELİYOR. İstemci `/veri/../etc/shadow` * yazabiliyor ve hedef bunu `/etc/shadow` olarak çözüyor; politikaya ham * dizgiyi vermek, korumayı kâğıt üzerinde bırakırdı. * * ⚠️ NEYİ ÇÖZEMEDİĞİMİZ DE AÇIK OLMALI: sembolik bağlar. Dosya sistemine * erişimimiz yok, dolayısıyla izinli bir dizindeki `link -> /etc` üzerinden * geçen bir yol bize izinli görünür. Bunu kapatmanın yolu her istekte * hedefe fazladan gidiş-dönüş olurdu; agentless duruşu ve gecikme hedefi * buna izin vermiyor. Sınır belgede aynı sertlikte yazılı.
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
* Session, tek bir SFTP kanalının iki yönünü izler. * * İki yön ayrı goroutine'lerden besleniyor (istemci→hedef ve hedef→ * istemci kopyaları paralel akıyor), bu yüzden durum kilit altında.
func NewSession ¶
NewSession, izleyiciyi kurar. emit her olay için çağrılıyor.
func (*Session) Finish ¶
func (s *Session) Finish()
* Finish, kanal kapanırken YARIM KALAN transferleri yazar. * * ⚠️ NEDEN ŞART: bağlantı transfer ortasında koparsa CLOSE hiç gelmez. * Bu olmadan, yarıda kesilen 1 GB'lık bir indirme denetim kaydında HİÇ * görünmezdi — yani veriyi çekip bağlantıyı koparmak, izi silmenin yolu * olurdu.
func (*Session) FromClient ¶
FromClient, istemci→hedef akışından gelen baytları verir.
func (*Session) FromClientTo ¶ added in v1.2.0
* FromClientTo, FromClient ile aynı işi yapıyor ve AYRICA iletimi * üstleniyor: hedefe gitmesi gereken aralıklar forward'a gidiyor, * reddedilen isteğin baytları hiç gitmiyor. * * ⚠️ ÇAĞIRAN DÖNÜŞTEN SONRA TakeDenials'I BOŞALTMALI. Reddedilen istek * hedefe gitmediği için hiçbir zaman cevaplanmayacak; istemciye postern'in * kendi cevabı gitmezse o istek kimliği sonsuza kadar açık kalır ve * istemci askıda bekler. * * ⚠️ DENETİMİN GÖRDÜĞÜ, HEDEFİN YAPABİLECEĞİNDEN ÖNCE. Bir paketin ilk * parçası hedefe gidebiliyor ama hedef paketi TAMAMLANMADAN işleyemiyor; * tamamlayan parça ise denetim olayı yazıldıktan sonra iletiliyor. Yani * "hedef bir isteği yaptıysa denetim onu görmüştür" değişmezi duruyor.
func (*Session) FromTarget ¶
FromTarget, hedef→istemci akışından gelen baytları verir.
func (*Session) SetPolicy ¶ added in v1.2.0
SetPolicy, isteklere karar verecek geri çağrıyı kurar. nil ise yol kuralı uygulanmıyor (salt-okuma kısıtı ayrı, bkz. SetReadOnly).
func (*Session) SetReadOnly ¶ added in v1.2.0
* SetReadOnly, oturumu hedefte HİÇBİR ŞEYİ DEĞİŞTİREMEZ hâle getirir. * * ⚠️ YOL POLİTİKASINDAN AYRI BİR KISIT. Roldeki kurallar "nereye" * sorusunu cevaplıyor; bu, "ne yapabilir" sorusunu. Bir kanalın * salt-okunur olması kullanıcının yetkisiyle değil, o KANALIN ne için * açıldığıyla ilgili. * * ⚠️ SARMALAYICI OLARAK YAZILAMAZDI ve sebebi ölçülebilir: FXP_WRITE * politikaya HİÇ sorulmuyor — tanıtıcı üzerinden yazma, açılışta karara * bağlandığı için politikaya götürülmüyor. Decider'ı saran bir kısıt o * isteği hiç görmezdi. Yazma bayraklı OPEN reddedilirse yazma tanıtıcısı * zaten oluşmaz; ama buna güvenmek, kısıtı HEDEFİN kendi kontrolüne * bırakmak demek — bir bastion'ın tam olarak yapmaması gereken şey.
func (*Session) TakeDenials ¶ added in v1.2.0
* TakeDenials, reddedilen isteklere üretilen STATUS paketlerini alır. * * ⚠️ ÇAĞIRAN BUNLARI OTURUM KİLİDİ DIŞINDA YAZMALI. Karar, veri yolunun * üstünde ve s.mu altında veriliyor; istemciye o kilidi tutarken yazmak, * okumayı durduran bir istemcide hedef→istemci yönünü de kilitlerdi.
func (*Session) TargetAtBoundary ¶ added in v1.2.0
* TargetAtBoundary, hedef→istemci akışının paket SINIRINDA olup olmadığı. * * ⚠️ NEDEN SORULUYOR: postern bazen istemciye KENDİ cevabını yazıyor * (reddedilen istekler). O baytları gerçek bir paketin ORTASINA sokmak * istemcinin çözümleyicisini bozar — paket yanlış yerden ayrışır ve * sonraki her bayt kayar. * * ⚠️ İKİ KOŞUL. lenHave == 0, çözümleyicinin paketler ARASINDA olduğunu * söylüyor: önek tamamlanmışsa (4) gövdenin ortasındayız, kısmen gelmişse * (1..3) önekin ortasındayız. got/need karşılaştırması bu bilgiyi tekrar * etmekten ibaret. * * ⚠️ AMA "HİÇ BAŞLAMADIK" SINIR DEĞİL, ve bu ayrım ölçülebilir bir arızayı * önlüyor: istemci INIT ile reddedilecek bir isteği boru hattıyla birlikte * gönderirse, hedef daha VERSION'ı yollamadan cevabımızı yazardık. * İstemcinin gördüğü ilk paket SSH_FXP_STATUS olurdu; OpenSSH'in sftp_init'i * yalnızca VERSION kabul ediyor ve fatal ile çıkıyor. * * ⚠️ ÇAĞIRAN, İSTEMCİYE YAZMAYI SERİ HÂLE GETİREN KİLİDİ TUTMALI. Aksi * hâlde cevap, yazılmış ama HENÜZ ÇÖZÜMLENMEMİŞ bir parçanın ardından * gelir ve bu fonksiyon bayat bir cevap verir.