test / test (push) Waiting to run
The security documentation's last open item of panel-dkim-signing (the owner's decision, 2026-10-16): go-milter v0.4.1 added every header of a session to a map of its own, emptied only on ABORT, and handed it to Headers - which no milter of the panel reads. Postfix bounds one header, not their number, so a message of nothing but headers up to the message size limit was held whole by the library in the sender check, the signer and the journal milter on 465/587 and in the inbound journal milter on port 25, where strangers send; the signer's 1 MiB refusal came after it was all in. third_party/go-milter is v0.4.1 from the module cache (BSD 2-Clause, LICENSE kept) with session.go changed: CodeHeader hands the header to Header and keeps nothing, CodeEOH hands Headers an empty map. PATCHES.md says what and why, and how to take a new upstream version. go.mod replaces the module with it; the Dockerfile copies third_party before "go mod download". TestTheLibraryKeepsNoHeaders holds it through the library's own client over two messages of one connection. Comments, security.md (the accepted risk becomes a note), development.md's library table, the plan and CHANGELOG follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
63 lines
1.7 KiB
Go
63 lines
1.7 KiB
Go
package milter
|
|
|
|
// Response represents a response structure returned by callback
|
|
// handlers to indicate how the milter server should proceed
|
|
type Response interface {
|
|
Response() *Message
|
|
Continue() bool
|
|
}
|
|
|
|
// SimpleResponse type to define list of pre-defined responses
|
|
type SimpleResponse byte
|
|
|
|
// Response returns a Message object reference
|
|
func (r SimpleResponse) Response() *Message {
|
|
return &Message{byte(r), nil}
|
|
}
|
|
|
|
// Continue to process milter messages only if current code is Continue
|
|
func (r SimpleResponse) Continue() bool {
|
|
return ActionCode(r) == ActContinue
|
|
}
|
|
|
|
// Define standard responses with no data
|
|
const (
|
|
RespAccept = SimpleResponse(ActAccept)
|
|
RespContinue = SimpleResponse(ActContinue)
|
|
RespDiscard = SimpleResponse(ActDiscard)
|
|
RespReject = SimpleResponse(ActReject)
|
|
RespTempFail = SimpleResponse(ActTempFail)
|
|
)
|
|
|
|
// CustomResponse is a response instance used by callback handlers to indicate
|
|
// how the milter should continue processing of current message
|
|
type CustomResponse struct {
|
|
code byte
|
|
data []byte
|
|
}
|
|
|
|
// Response returns message instance with data
|
|
func (c *CustomResponse) Response() *Message {
|
|
return &Message{c.code, c.data}
|
|
}
|
|
|
|
// Continue returns false if milter chain should be stopped, true otherwise
|
|
func (c *CustomResponse) Continue() bool {
|
|
for _, q := range []ActionCode{ActAccept, ActDiscard, ActReject, ActTempFail} {
|
|
if c.code == byte(q) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// NewResponse generates a new CustomResponse suitable for WritePacket
|
|
func NewResponse(code byte, data []byte) *CustomResponse {
|
|
return &CustomResponse{code, data}
|
|
}
|
|
|
|
// NewResponseStr generates a new CustomResponse with string payload
|
|
func NewResponseStr(code byte, data string) *CustomResponse {
|
|
return NewResponse(code, []byte(data+null))
|
|
}
|