diff --git a/docs/sliver-docs/pages/docs/md/Getting Started.md b/docs/sliver-docs/pages/docs/md/Getting Started.md index 062ab5e798..1698ddd371 100644 --- a/docs/sliver-docs/pages/docs/md/Getting Started.md +++ b/docs/sliver-docs/pages/docs/md/Getting Started.md @@ -10,7 +10,7 @@ For a Linux server, you can also use the one liner installation `curl https://sl {"src": "/asciinema/install-1.cast", "cols": "132"} ``` -If you install Sliver via the one liner, you can check that the server service is running using `systemctl status sliver`. Note that the Sliver service is not configured to start automatically on boot by default (i.e., if you reboot the server you'll need to start the service again using `systemctrl start sliver`): +If you install Sliver via the one liner, you can check that the server service is running using `systemctl status sliver`. Note that the Sliver service is not configured to start automatically on boot by default (i.e., if you reboot the server you'll need to start the service again using `systemctl start sliver`): ```asciinema {"src": "/asciinema/service-status-1.cast", "cols": "132", "rows": "14", "idleTimeLimit": 8} diff --git a/docs/sliver-docs/public/install b/docs/sliver-docs/public/install index 2f8df8176d..b96b5ac9ff 100644 --- a/docs/sliver-docs/public/install +++ b/docs/sliver-docs/public/install @@ -22,8 +22,8 @@ elif command -v yum &> /dev/null; then # Redhat-based OS (Fedora, CentOS, RHEL) INSTALLER=(yum -y) elif command -v pacman &>/dev/null; then # Arch-based (Manjaro, Garuda, Blackarch) echo "Installing dependencies using pacman..." - pacman -S mingw-w64-gcc mingw-w64-binutils mingw-w64-headers - INSTALLER=(pacman -S) + pacman --noconfirm -S mingw-w64-gcc mingw-w64-binutils mingw-w64-headers + INSTALLER=(pacman --noconfirm -S) else echo "Unsupported OS, exiting" exit diff --git a/go.mod b/go.mod index 5392819132..4101b6b3ef 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/Binject/universal v0.0.0-20220519011857-bea739e758c0 github.com/Ne0nd0g/go-clr v1.0.3 github.com/alecthomas/chroma v0.10.0 - github.com/cheggaaa/pb/v3 v3.1.2 + github.com/cheggaaa/pb/v3 v3.1.5 github.com/chromedp/cdproto v0.0.0-20240426225625-909263490071 github.com/chromedp/chromedp v0.9.5 github.com/fatih/color v1.16.0 @@ -49,7 +49,7 @@ require ( github.com/yiya1989/sshkrb5 v0.0.1 golang.org/x/crypto v0.23.0 golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f - golang.org/x/net v0.24.0 + golang.org/x/net v0.25.0 golang.org/x/sys v0.20.0 golang.org/x/term v0.20.0 golang.org/x/text v0.15.0 diff --git a/go.sum b/go.sum index 0a2e51fe8a..0742f00a9a 100644 --- a/go.sum +++ b/go.sum @@ -86,8 +86,8 @@ github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZx github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cheggaaa/pb/v3 v3.1.2 h1:FIxT3ZjOj9XJl0U4o2XbEhjFfZl7jCVCDOGq1ZAB7wQ= -github.com/cheggaaa/pb/v3 v3.1.2/go.mod h1:SNjnd0yKcW+kw0brSusraeDd5Bf1zBfxAzTL2ss3yQ4= +github.com/cheggaaa/pb/v3 v3.1.5 h1:QuuUzeM2WsAqG2gMqtzaWithDJv0i+i6UlnwSCI4QLk= +github.com/cheggaaa/pb/v3 v3.1.5/go.mod h1:CrxkeghYTXi1lQBEI7jSn+3svI3cuc19haAj6jM60XI= github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= github.com/chromedp/cdproto v0.0.0-20240426225625-909263490071 h1:RdCf9hH3xq5vJifrjGB7zQlFkdRB3pAppcX2helDq2U= github.com/chromedp/cdproto v0.0.0-20240426225625-909263490071/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= @@ -454,8 +454,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= diff --git a/server/db/helpers.go b/server/db/helpers.go index 945faa6e20..727d94cf84 100644 --- a/server/db/helpers.go +++ b/server/db/helpers.go @@ -27,6 +27,7 @@ import ( "crypto/sha256" "encoding/hex" "errors" + "fmt" "os" "path/filepath" "strings" @@ -258,7 +259,7 @@ func ImplantProfileByName(name string) (*clientpb.ImplantProfile, error) { return nil, err } err = Session().Where(models.ImplantConfig{ - ImplantProfileID: profile.ID, + ImplantProfileID: &profile.ID, }).First(&config).Error if err != nil { return nil, err @@ -367,7 +368,7 @@ func LoadHTTPC2ConfigByName(name string) (*clientpb.HTTPC2Config, error) { // load headers c2ImplantHeaders := []models.HttpC2Header{} err = Session().Where(&models.HttpC2Header{ - HttpC2ImplantConfigID: c2ImplantConfig.ID, + HttpC2ImplantConfigID: &c2ImplantConfig.ID, }).Find(&c2ImplantHeaders).Error if err != nil { return nil, err @@ -397,7 +398,7 @@ func LoadHTTPC2ConfigByName(name string) (*clientpb.HTTPC2Config, error) { // load headers c2ServerHeaders := []models.HttpC2Header{} err = Session().Where(&models.HttpC2Header{ - HttpC2ServerConfigID: c2ServerConfig.ID, + HttpC2ServerConfigID: &c2ServerConfig.ID, }).Find(&c2ServerHeaders).Error if err != nil { return nil, err @@ -471,7 +472,7 @@ func HTTPC2ConfigUpdate(newConf *clientpb.HTTPC2Config, oldConf *clientpb.HTTPC2 } err = Session().Where(&models.HttpC2Header{ - HttpC2ServerConfigID: serverID, + HttpC2ServerConfigID: &serverID, }).Delete(&models.HttpC2Header{}) if err.Error != nil { return err.Error @@ -495,7 +496,7 @@ func HTTPC2ConfigUpdate(newConf *clientpb.HTTPC2Config, oldConf *clientpb.HTTPC2 } for _, header := range c2Config.ServerConfig.Headers { - header.HttpC2ServerConfigID = serverID + header.HttpC2ServerConfigID = &serverID err = Session().Clauses(clause.OnConflict{ UpdateAll: true, }).Create(&header) @@ -591,6 +592,35 @@ func ListenerJobs() ([]*clientpb.ListenerJob, error) { } func DeleteListener(JobID uint32) error { + // Determine which type of listener this is and delete its record from the corresponding table + var deleteErr error + // JobID is unique so if the JobID exists, it is the only record in the table with that JobID + listener := &models.ListenerJob{} + result := Session().Where(&models.ListenerJob{JobID: JobID}).First(&listener) + if result.Error != nil { + return result.Error + } + if listener == nil { + return fmt.Errorf("Job ID %d not found in database", JobID) + } + listenerID := listener.ID + switch listener.Type { + case constants.HttpStr, constants.HttpsStr: + deleteErr = Session().Where(&models.HTTPListener{ListenerJobID: listenerID}).Delete(&models.HTTPListener{}).Error + case constants.DnsStr: + deleteErr = Session().Where(&models.DNSListener{ListenerJobID: listenerID}).Delete(&models.DNSListener{}).Error + case constants.MtlsStr: + deleteErr = Session().Where(&models.MtlsListener{ListenerJobID: listenerID}).Delete(&models.MtlsListener{}).Error + case constants.WGStr: + deleteErr = Session().Where(&models.WGListener{ListenerJobID: listenerID}).Delete(&models.WGListener{}).Error + case constants.MultiplayerModeStr: + deleteErr = Session().Where(&models.MultiplayerListener{ListenerJobID: listenerID}).Delete(&models.MultiplayerListener{}).Error + } + + if deleteErr != nil { + return deleteErr + } + return Session().Where(&models.ListenerJob{JobID: JobID}).Delete(&models.ListenerJob{}).Error } @@ -641,6 +671,9 @@ func DeleteProfile(name string) error { uuid, _ := uuid.FromString(profile.Config.ID) + // delete linked ImplantC2 + err = Session().Where(&models.ImplantC2{ImplantConfigID: uuid}).Delete(&models.ImplantC2{}).Error + // delete linked ImplantConfig err = Session().Where(&models.ImplantConfig{ID: uuid}).Delete(&models.ImplantConfig{}).Error diff --git a/server/db/models/host.go b/server/db/models/host.go index d16ca4396e..578aca7d35 100644 --- a/server/db/models/host.go +++ b/server/db/models/host.go @@ -29,7 +29,7 @@ import ( // Host - Represents a host machine type Host struct { ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"` - HostUUID uuid.UUID `gorm:"type:uuid;"` + HostUUID uuid.UUID `gorm:"type:uuid;unique"` CreatedAt time.Time `gorm:"->;<-:create;"` Hostname string diff --git a/server/db/models/http-c2.go b/server/db/models/http-c2.go index 18d816b036..d45d72ac7c 100644 --- a/server/db/models/http-c2.go +++ b/server/db/models/http-c2.go @@ -203,9 +203,9 @@ func (h *HttpC2Cookie) ToProtobuf() *clientpb.HTTPC2Cookie { // HttpC2Header - HTTP C2 Header (server and implant) type HttpC2Header struct { - ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"` - HttpC2ServerConfigID uuid.UUID `gorm:"type:uuid;"` - HttpC2ImplantConfigID uuid.UUID `gorm:"type:uuid;"` + ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"` + HttpC2ServerConfigID *uuid.UUID `gorm:"type:uuid;"` + HttpC2ImplantConfigID *uuid.UUID `gorm:"type:uuid;"` Method string Name string diff --git a/server/db/models/implant.go b/server/db/models/implant.go index cccda8d286..2c244cab6d 100644 --- a/server/db/models/implant.go +++ b/server/db/models/implant.go @@ -144,7 +144,7 @@ func ImplantBuildFromProtobuf(ib *clientpb.ImplantBuild) *ImplantBuild { // ImplantConfig - An implant build configuration type ImplantConfig struct { ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"` - ImplantProfileID uuid.UUID + ImplantProfileID *uuid.UUID ImplantBuilds []ImplantBuild CreatedAt time.Time `gorm:"->;<-:create;"` @@ -237,9 +237,8 @@ func (ic *ImplantConfig) ToProtobuf() *clientpb.ImplantConfig { implantBuilds = append(implantBuilds, implantBuild.ToProtobuf()) } config := &clientpb.ImplantConfig{ - ID: ic.ID.String(), - ImplantBuilds: implantBuilds, - ImplantProfileID: ic.ImplantProfileID.String(), + ID: ic.ID.String(), + ImplantBuilds: implantBuilds, IsBeacon: ic.IsBeacon, BeaconInterval: ic.BeaconInterval, @@ -286,6 +285,11 @@ func (ic *ImplantConfig) ToProtobuf() *clientpb.ImplantConfig { IncludeWG: ic.IncludeWG, IncludeTCP: ic.IncludeTCP, } + + if ic.ImplantProfileID != nil { + config.ImplantProfileID = ic.ImplantProfileID.String() + } + // Copy Canary Domains config.CanaryDomains = []string{} for _, canaryDomain := range ic.CanaryDomains { @@ -432,7 +436,11 @@ func ImplantConfigFromProtobuf(pbConfig *clientpb.ImplantConfig) *ImplantConfig cfg.ID = id cfg.ImplantBuilds = implantBuilds profileID, _ := uuid.FromString(pbConfig.ImplantProfileID) - cfg.ImplantProfileID = profileID + if profileID == uuid.Nil { + cfg.ImplantProfileID = nil + } else { + cfg.ImplantProfileID = &profileID + } cfg.IsBeacon = pbConfig.IsBeacon cfg.BeaconInterval = pbConfig.BeaconInterval diff --git a/server/db/sql.go b/server/db/sql.go index 673e53ab4e..6cb730f47f 100644 --- a/server/db/sql.go +++ b/server/db/sql.go @@ -50,7 +50,14 @@ func newDBClient() *gorm.DB { panic(fmt.Sprintf("Unknown DB Dialect: '%s'", dbConfig.Dialect)) } - err := dbClient.AutoMigrate( + // We cannot pass all of these into AutoMigrate at once because if one fails, subsequent models will not be created + var allDBModels []interface{} = append(make([]interface{}, 0), + &models.HttpC2Header{}, + &models.HttpC2ServerConfig{}, + &models.HttpC2ImplantConfig{}, + &models.HttpC2Config{}, + &models.HttpC2URLParameter{}, + &models.HttpC2PathSegment{}, &models.Beacon{}, &models.BeaconTask{}, &models.DNSCanary{}, @@ -62,30 +69,25 @@ func newDBClient() *gorm.DB { &models.CrackFileChunk{}, &models.Certificate{}, &models.Host{}, - &models.HttpC2Config{}, - &models.HttpC2ImplantConfig{}, - &models.HttpC2ServerConfig{}, - &models.HttpC2Header{}, - &models.HttpC2PathSegment{}, + &models.KeyValue{}, + &models.WGKeys{}, + &models.WGPeer{}, + &models.ResourceID{}, &models.HttpC2Cookie{}, - &models.HttpC2URLParameter{}, &models.IOC{}, &models.ExtensionData{}, - &models.ImplantBuild{}, &models.ImplantProfile{}, &models.ImplantConfig{}, + &models.ImplantBuild{}, &models.ImplantC2{}, &models.EncoderAsset{}, &models.KeyExHistory{}, - &models.KeyValue{}, &models.CanaryDomain{}, &models.Loot{}, &models.Credential{}, &models.Operator{}, &models.Website{}, &models.WebContent{}, - &models.WGKeys{}, - &models.WGPeer{}, &models.ListenerJob{}, &models.HTTPListener{}, &models.DNSListener{}, @@ -94,10 +96,15 @@ func newDBClient() *gorm.DB { &models.MtlsListener{}, &models.DnsDomain{}, &models.MonitoringProvider{}, - &models.ResourceID{}, ) - if err != nil { - clientLog.Error(err) + + var err error + + for _, model := range allDBModels { + err = dbClient.AutoMigrate(model) + if err != nil { + clientLog.Error(err) + } } // Get generic database object sql.DB to use its functions diff --git a/server/generate/implants.go b/server/generate/implants.go index 13169904fc..2d9e6ef34a 100644 --- a/server/generate/implants.go +++ b/server/generate/implants.go @@ -77,7 +77,11 @@ func ImplantConfigSave(config *clientpb.ImplantConfig) (*clientpb.ImplantConfig, } else { id, _ := uuid.FromString(dbConfig.ImplantProfileID) - modelConfig.ImplantProfileID = id + if id == uuid.Nil { + modelConfig.ImplantProfileID = nil + } else { + modelConfig.ImplantProfileID = &id + } // this avoids gorm saving duplicate c2 objects ... tempC2 := modelConfig.C2 diff --git a/server/generate/profiles.go b/server/generate/profiles.go index eed64c18c9..f8e8417f1d 100644 --- a/server/generate/profiles.go +++ b/server/generate/profiles.go @@ -54,7 +54,11 @@ func SaveImplantProfile(pbProfile *clientpb.ImplantProfile) (*clientpb.ImplantPr profile.ImplantConfig.ID = configID profileID, _ := uuid.FromString(dbProfile.ID) - profile.ImplantConfig.ImplantProfileID = profileID + if profileID == uuid.Nil { + profile.ImplantConfig.ImplantProfileID = nil + } else { + profile.ImplantConfig.ImplantProfileID = &profileID + } for _, c2 := range dbProfile.Config.C2 { id, _ := uuid.FromString(c2.ID) diff --git a/vendor/github.com/cheggaaa/pb/v3/pool_win.go b/vendor/github.com/cheggaaa/pb/v3/pool_win.go index 35a61474a9..7002e85fc3 100644 --- a/vendor/github.com/cheggaaa/pb/v3/pool_win.go +++ b/vendor/github.com/cheggaaa/pb/v3/pool_win.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package pb @@ -5,6 +6,7 @@ package pb import ( "fmt" "log" + "strings" "github.com/cheggaaa/pb/v3/termutil" ) @@ -24,17 +26,25 @@ func (p *Pool) print(first bool) bool { } coords.X = 0 - err = termutil.SetCursorPos(coords) + err = termutil.SetCursorPos(coords) if err != nil { log.Panic(err) } } + cols, err := termutil.TerminalWidth() + if err != nil { + cols = defaultBarWidth + } isFinished := true for _, bar := range p.bars { if !bar.IsFinished() { isFinished = false } - out += fmt.Sprintf("\r%s\n", bar.String()) + result := bar.String() + if r := cols - CellCount(result); r > 0 { + result += strings.Repeat(" ", r) + } + out += fmt.Sprintf("\r%s\n", result) } if p.Output != nil { fmt.Fprint(p.Output, out) diff --git a/vendor/github.com/cheggaaa/pb/v3/pool_x.go b/vendor/github.com/cheggaaa/pb/v3/pool_x.go index 4350301555..cae9758381 100644 --- a/vendor/github.com/cheggaaa/pb/v3/pool_x.go +++ b/vendor/github.com/cheggaaa/pb/v3/pool_x.go @@ -1,3 +1,4 @@ +//go:build linux || darwin || freebsd || netbsd || openbsd || solaris || dragonfly || plan9 || aix // +build linux darwin freebsd netbsd openbsd solaris dragonfly plan9 aix package pb @@ -5,6 +6,7 @@ package pb import ( "fmt" "os" + "strings" "github.com/cheggaaa/pb/v3/termutil" ) @@ -31,7 +33,11 @@ func (p *Pool) print(first bool) bool { isFinished = false } bar.SetWidth(cols) - out += fmt.Sprintf("\r%s\n", bar.String()) + result := bar.String() + if r := cols - CellCount(result); r > 0 { + result += strings.Repeat(" ", r) + } + out += fmt.Sprintf("\r%s\n", result) } if p.Output != nil { fmt.Fprint(p.Output, out) diff --git a/vendor/github.com/cheggaaa/pb/v3/termutil/term_win.go b/vendor/github.com/cheggaaa/pb/v3/termutil/term_win.go index 75c7e2c398..99397a0dcd 100644 --- a/vendor/github.com/cheggaaa/pb/v3/termutil/term_win.go +++ b/vendor/github.com/cheggaaa/pb/v3/termutil/term_win.go @@ -138,9 +138,8 @@ func lockEcho() (err error) { } newState := oldState - const ENABLE_ECHO_INPUT = 0x0004 const ENABLE_LINE_INPUT = 0x0002 - newState = newState & (^(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)) + newState = newState & (^ENABLE_LINE_INPUT) if _, _, e := syscall.Syscall(setConsoleMode.Addr(), 2, uintptr(syscall.Stdout), uintptr(newState), 0); e != 0 { err = fmt.Errorf("Can't set terminal settings: %v", e) return diff --git a/vendor/golang.org/x/net/http/httpguts/httplex.go b/vendor/golang.org/x/net/http/httpguts/httplex.go index 6e071e8524..9b4de94019 100644 --- a/vendor/golang.org/x/net/http/httpguts/httplex.go +++ b/vendor/golang.org/x/net/http/httpguts/httplex.go @@ -12,7 +12,7 @@ import ( "golang.org/x/net/idna" ) -var isTokenTable = [127]bool{ +var isTokenTable = [256]bool{ '!': true, '#': true, '$': true, @@ -93,12 +93,7 @@ var isTokenTable = [127]bool{ } func IsTokenRune(r rune) bool { - i := int(r) - return i < len(isTokenTable) && isTokenTable[i] -} - -func isNotToken(r rune) bool { - return !IsTokenRune(r) + return r < utf8.RuneSelf && isTokenTable[byte(r)] } // HeaderValuesContainsToken reports whether any string in values @@ -202,8 +197,8 @@ func ValidHeaderFieldName(v string) bool { if len(v) == 0 { return false } - for _, r := range v { - if !IsTokenRune(r) { + for i := 0; i < len(v); i++ { + if !isTokenTable[v[i]] { return false } } diff --git a/vendor/golang.org/x/net/http2/frame.go b/vendor/golang.org/x/net/http2/frame.go index 43557ab7e9..105c3b279c 100644 --- a/vendor/golang.org/x/net/http2/frame.go +++ b/vendor/golang.org/x/net/http2/frame.go @@ -490,6 +490,9 @@ func terminalReadFrameError(err error) bool { // returned error is ErrFrameTooLarge. Other errors may be of type // ConnectionError, StreamError, or anything else from the underlying // reader. +// +// If ReadFrame returns an error and a non-nil Frame, the Frame's StreamID +// indicates the stream responsible for the error. func (fr *Framer) ReadFrame() (Frame, error) { fr.errDetail = nil if fr.lastFrame != nil { @@ -1521,7 +1524,7 @@ func (fr *Framer) maxHeaderStringLen() int { // readMetaFrame returns 0 or more CONTINUATION frames from fr and // merge them into the provided hf and returns a MetaHeadersFrame // with the decoded hpack values. -func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) { +func (fr *Framer) readMetaFrame(hf *HeadersFrame) (Frame, error) { if fr.AllowIllegalReads { return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders") } @@ -1592,7 +1595,7 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) { } // It would be nice to send a RST_STREAM before sending the GOAWAY, // but the structure of the server's frame writer makes this difficult. - return nil, ConnectionError(ErrCodeProtocol) + return mh, ConnectionError(ErrCodeProtocol) } // Also close the connection after any CONTINUATION frame following an @@ -1604,11 +1607,11 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) { } // It would be nice to send a RST_STREAM before sending the GOAWAY, // but the structure of the server's frame writer makes this difficult. - return nil, ConnectionError(ErrCodeProtocol) + return mh, ConnectionError(ErrCodeProtocol) } if _, err := hdec.Write(frag); err != nil { - return nil, ConnectionError(ErrCodeCompression) + return mh, ConnectionError(ErrCodeCompression) } if hc.HeadersEnded() { @@ -1625,7 +1628,7 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) { mh.HeadersFrame.invalidate() if err := hdec.Close(); err != nil { - return nil, ConnectionError(ErrCodeCompression) + return mh, ConnectionError(ErrCodeCompression) } if invalid != nil { fr.errDetail = invalid diff --git a/vendor/golang.org/x/net/http2/server.go b/vendor/golang.org/x/net/http2/server.go index ce2e8b40ee..c5d0810813 100644 --- a/vendor/golang.org/x/net/http2/server.go +++ b/vendor/golang.org/x/net/http2/server.go @@ -732,11 +732,7 @@ func isClosedConnError(err error) bool { return false } - // TODO: remove this string search and be more like the Windows - // case below. That might involve modifying the standard library - // to return better error types. - str := err.Error() - if strings.Contains(str, "use of closed network connection") { + if errors.Is(err, net.ErrClosed) { return true } @@ -1482,6 +1478,11 @@ func (sc *serverConn) processFrameFromReader(res readFrameResult) bool { sc.goAway(ErrCodeFlowControl) return true case ConnectionError: + if res.f != nil { + if id := res.f.Header().StreamID; id > sc.maxClientStreamID { + sc.maxClientStreamID = id + } + } sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev) sc.goAway(ErrCode(ev)) return true // goAway will handle shutdown diff --git a/vendor/golang.org/x/net/http2/transport.go b/vendor/golang.org/x/net/http2/transport.go index ce375c8c75..2fa49490c9 100644 --- a/vendor/golang.org/x/net/http2/transport.go +++ b/vendor/golang.org/x/net/http2/transport.go @@ -936,7 +936,20 @@ func (cc *ClientConn) setGoAway(f *GoAwayFrame) { } last := f.LastStreamID for streamID, cs := range cc.streams { - if streamID > last { + if streamID <= last { + // The server's GOAWAY indicates that it received this stream. + // It will either finish processing it, or close the connection + // without doing so. Either way, leave the stream alone for now. + continue + } + if streamID == 1 && cc.goAway.ErrCode != ErrCodeNo { + // Don't retry the first stream on a connection if we get a non-NO error. + // If the server is sending an error on a new connection, + // retrying the request on a new one probably isn't going to work. + cs.abortStreamLocked(fmt.Errorf("http2: Transport received GOAWAY from server ErrCode:%v", cc.goAway.ErrCode)) + } else { + // Aborting the stream with errClentConnGotGoAway indicates that + // the request should be retried on a new connection. cs.abortStreamLocked(errClientConnGotGoAway) } } diff --git a/vendor/modules.txt b/vendor/modules.txt index 3f3c2c6269..e0ac394e9d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -203,7 +203,7 @@ github.com/aws/smithy-go/waiter # github.com/bits-and-blooms/bitset v1.13.0 ## explicit; go 1.16 github.com/bits-and-blooms/bitset -# github.com/cheggaaa/pb/v3 v3.1.2 +# github.com/cheggaaa/pb/v3 v3.1.5 ## explicit; go 1.17 github.com/cheggaaa/pb/v3 github.com/cheggaaa/pb/v3/termutil @@ -820,7 +820,7 @@ golang.org/x/exp/slog/internal/buffer # golang.org/x/mod v0.17.0 ## explicit; go 1.18 golang.org/x/mod/semver -# golang.org/x/net v0.24.0 +# golang.org/x/net v0.25.0 ## explicit; go 1.18 golang.org/x/net/bpf golang.org/x/net/dns/dnsmessage