Documentation
¶
Overview ¶
Package dnp3 is DNP3 (IEEE Std 1815-2012) in pure Go: a master and an outstation over TCP (optionally TLS), UDP or a serial line, with their own data link, transport and application layers, the object library, and Secure Authentication version 5 on both sides.
The layers:
- Data link (link.go, clause 9): frames with block CRCs, a parser that resynchronises after noise, primary and secondary stations with FCB/FCV state, confirmed and unconfirmed user data, link status.
- Transport (transport.go, clause 8): segmenting and reassembly.
- Application (app.go, objects.go, clauses 4 to 6 and 11, Annex A): fragments, function codes, qualifiers, internal indications, and object encoding and decoding (static, event, command, frozen, octet string, file, data set, device attribute and security objects).
- Master (master.go): Dial a MasterConfig, then Request, SelectOperate, ChangeSessionKeys and ChangeUpdateKey; unsolicited responses are confirmed and handed to OnUnsolicited.
- Outstation (outstation.go, outdb.go, outfile.go, outnet.go): a PointDB with per-class event buffers (EventStore makes them durable), an Association per master that answers polls, controls, time synchronisation, freeze, file transfer, data sets and unsolicited reporting through a Handler, and an OutstationNet that routes frames from streams (TCP, TLS, serial) and UDP sockets.
- Secure Authentication v5 (auth.go, ostauth.go, updatekey.go, gmac.go, usercert.go, clause 7): session keys, challenges and replies, aggressive mode, the security statistics and their limits, update key change (symmetric and asymmetric), and g120v8 user certificates read through an IEC 62351-8 role authority.
Security services come in through the small interfaces of github.com/cB-Sigma/iotsec: a TLS client or server profile (MasterConfig.TLS; the outstation's listener is the caller's), a Dialer, an Auditor for security events (SetAuditor) and a RoleAuthority for user certificates (OutstationAuthConfig.Roles). Each is optional.
A simulated outstation for tests, with a command that serves it, is the separate module github.com/cB-Sigma/dnp3-sim.
Index ¶
- Constants
- Variables
- func ActivateStatusName(c uint8) string
- func AppendAttribute(out []byte, variation uint8, set uint8, value any) []byte
- func AppendAuthObject(out []byte, variation uint8, data []byte) []byte
- func AppendElements(out []byte, els []DescElement) []byte
- func AppendHeader(out []byte, group, variation, qual uint8, a, b uint32) []byte
- func AppendKeyStatus(out []byte, k KeyStatus) []byte
- func AppendTime48(out []byte, t time.Time) []byte
- func AssignClass(sets []ClassAssignment) []byte
- func AttributeName(variation uint8) string
- func AuthErrorName(c uint8) string
- func CRC(b []byte) uint16
- func CRCTableEntry(i byte) uint16
- func CTLSStatus(v []byte) uint8
- func CertifyStatus(method uint8, key []byte, master uint16, u UserStatus) ([]byte, error)
- func ChallengeLen(method uint8) int
- func ClassRequest(classes ...int) []byte
- func ConfirmationMAC(method uint8, newKey []byte, receiver string, senderChal, receiverChal []byte, ...) ([]byte, error)
- func ConfirmationMACIV(method uint8, newKey, iv []byte, receiver string, ...) ([]byte, error)
- func CriticalMandatory(fc byte) bool
- func DSASign(method uint8, key *dsa.PrivateKey, data []byte) ([]byte, error)
- func DSAVerify(method uint8, key *dsa.PublicKey, data, sig []byte) bool
- func DataSetType(name string) (uint8, bool)
- func DataSetValue(typ uint8, v []byte) (any, error)
- func EncodeBlock(group, variation, qual uint8, pts []Point, cto ...time.Time) ([]byte, error)
- func EncodeDataSetValue(e DescElement, v any) ([]byte, error)
- func EncodePointRefs(id uint32, refs []PointRef) []byte
- func Family(group uint8) string
- func FilePath(name string) (string, bool)
- func FileStatusName(s uint8) string
- func FuncName(fc byte) string
- func GMAC(key, iv []byte, parts ...[]byte) ([]byte, error)
- func GMACIV(sender, usr uint16, ksq, csq uint32) []byte
- func GMACMethod(method uint8) bool
- func IsBroadcast(a uint16) bool
- func IsReservedAddress(a uint16) bool
- func IssueDSAUserCertificate(method uint8, key *dsa.PrivateKey, issuer string, user string, spki []byte, ...) ([]byte, error)
- func Known(group, variation uint8) bool
- func MAC(mal uint8, key []byte, parts ...[]byte) ([]byte, error)
- func MACByName(name string) uint8
- func MACIV(mal uint8, key, iv []byte, parts ...[]byte) ([]byte, error)
- func MACLen(mal uint8) int
- func MarshalDSAPublicKey(pub *dsa.PublicKey) ([]byte, error)
- func MethodHash(method uint8) (func() hash.Hash, int, error)
- func NoResponse(fc byte) bool
- func ObjectSize(group, variation uint8) int
- func PackedBits(group, variation uint8) int
- func ParseAuthObject(b []byte) (uint8, []byte, error)
- func ParseSessionKeyData(b []byte) (ctrl, mon, keyStatus []byte, err error)
- func PointGroup(typ string) ([2]uint8, bool)
- func PointTypeOf(group uint8) string
- func Segment(apdu []byte, seq *uint8) [][]byte
- func SelfSignedDSAAuthority(key *dsa.PrivateKey, name string, notBefore, notAfter time.Time) ([]byte, error)
- func SerialParams(u *url.URL) (dev string, baud int, parity string, err error)
- func SessionKeyData(ctrl, mon, keyStatus []byte) []byte
- func SetAuditor(r iotsec.Auditor)
- func SignatureData(outstation string, masterChal, ostnChal []byte, ksq uint32, usr uint16, ...) []byte
- func SplitAggressive(objects []byte) (req []byte, inner []byte, mac []byte, macAt int, ok bool)
- func StatisticName(i uint32) string
- func StatusName(s uint8) string
- func Symmetric(method uint8) bool
- func Time48(b []byte) time.Time
- func UnwrapKey(kek, wrapped []byte) ([]byte, error)
- func UpdateKeyData(name string, key, ostnChallenge []byte, pad bool) []byte
- func ValidQualifier(q uint8) bool
- func WrapKey(kek, key []byte) ([]byte, error)
- type ActivateStatus
- type Association
- func (a *Association) Accepts(dest uint16) bool
- func (a *Association) Attach(l OutLink)
- func (a *Association) Deliver(f Frame)
- func (a *Association) Detach(l OutLink)
- func (a *Association) Idle() time.Duration
- func (a *Association) KeepAlive()
- func (a *Association) Linked() bool
- func (a *Association) Master() uint16
- func (a *Association) Run(ctx context.Context)
- func (a *Association) Status() map[string]any
- func (a *Association) String() string
- type AsymmetricAuthority
- type Auth
- type AuthConfig
- type AuthError
- type Authority
- type Block
- type CROB
- type CertifiedUser
- type Challenge
- type Channel
- type ClassAssignment
- type ClassScan
- type ControlRequest
- type DBPoint
- type DataSet
- type DataSetControl
- type DataSetDef
- type DescElement
- type Descriptor
- type Event
- type EventBuffer
- func (b *EventBuffer) Add(ctx context.Context, e Event)
- func (b *EventBuffer) Capacity(class int) int
- func (b *EventBuffer) Classes(except map[int64]bool) map[int]bool
- func (b *EventBuffer) Counts() map[int]int
- func (b *EventBuffer) Len() int
- func (b *EventBuffer) Load(ctx context.Context) error
- func (b *EventBuffer) Overflow() bool
- func (b *EventBuffer) Pending(classes map[int]bool, limit int) []Event
- func (b *EventBuffer) Remove(ctx context.Context, ids []int64)
- type EventStore
- type FileAuth
- type FileClient
- func (c *FileClient) Delete(ctx context.Context, name string) error
- func (c *FileClient) Info(ctx context.Context, name string) (FileDescriptor, error)
- func (c *FileClient) List(ctx context.Context, dir string) ([]FileDescriptor, error)
- func (c *FileClient) ReadFile(ctx context.Context, name string) ([]byte, error)
- func (c *FileClient) WriteFile(ctx context.Context, name string, data []byte) error
- type FileCommand
- type FileDescriptor
- type FileInfo
- type FileRights
- type FileStatus
- type FileStore
- type FileTransport
- type FileTransportStatus
- type FileUser
- type Fragment
- type Frame
- type Handler
- type Header
- type IIN
- type KeyStatus
- type LinkAction
- type LinkParser
- type Master
- func (m *Master) Auth() *Auth
- func (m *Master) ChangeSessionKeys(ctx context.Context) error
- func (m *Master) ChangeUpdateKey(ctx context.Context, c UpdateKeyChange) error
- func (m *Master) Close() error
- func (m *Master) Done() <-chan struct{}
- func (m *Master) Err() error
- func (m *Master) IIN() IIN
- func (m *Master) LearnedAddress() (uint16, bool)
- func (m *Master) Quiet(d time.Duration)
- func (m *Master) Request(ctx context.Context, fc byte, objects []byte) ([]Fragment, error)
- func (m *Master) RunSession(ctx context.Context, cfg SessionConfig) error
- func (m *Master) SelectOperate(ctx context.Context, objects []byte, within time.Duration, ...) error
- func (m *Master) SyncTime(ctx context.Context, lan bool) error
- type MasterConfig
- type OutLink
- type OutstationAuth
- func (a *OutstationAuth) RecentSecurityEvents() ([]SecurityEventEntry, uint64)
- func (a *OutstationAuth) SAState() (string, time.Time)
- func (a *OutstationAuth) SetRSAKey(k *rsa.PrivateKey)
- func (a *OutstationAuth) Statistics() [NumSecurityStatistics]uint32
- func (a *OutstationAuth) Summary() map[string]any
- func (a *OutstationAuth) Users() []OutstationUser
- type OutstationAuthConfig
- type OutstationConfig
- type OutstationFiles
- type OutstationNet
- type OutstationUser
- type Point
- type PointDB
- func (db *PointDB) AddEvent(ctx context.Context, e Event)
- func (db *PointDB) Assign(typ string, indexes []uint32, class int) (missing bool)
- func (db *PointDB) Attach(b *EventBuffer)
- func (db *PointDB) DataSet(id uint32) (DataSetDef, bool)
- func (db *PointDB) DataSetIDs() []uint32
- func (db *PointDB) Define(p DBPoint) error
- func (db *PointDB) DefineDataSet(d DataSetDef) error
- func (db *PointDB) DefinePrototype(p Descriptor) error
- func (db *PointDB) Detach(b *EventBuffer)
- func (db *PointDB) Flat(id uint32) ([]DescElement, error)
- func (db *PointDB) Freeze(ctx context.Context, indexes []uint32, clear bool, at time.Time) []uint32
- func (db *PointDB) Point(typ string, index uint32) (DBPoint, bool)
- func (db *PointDB) Points(typ string) []DBPoint
- func (db *PointDB) Prototype(id uint32) (Descriptor, bool)
- func (db *PointDB) PrototypeIDs() []uint32
- func (db *PointDB) SetDataSet(ctx context.Context, id uint32, vals [][]byte, t time.Time, event bool) error
- func (db *PointDB) SetDeadband(index uint32, v float64) bool
- func (db *PointDB) SetTimeAndInterval(index uint32, ti TimeAndInterval) error
- func (db *PointDB) TimeAndInterval(index uint32) (TimeAndInterval, bool)
- func (db *PointDB) Types() []string
- func (db *PointDB) Update(ctx context.Context, typ string, index uint32, v float64, raw []byte, ...) (bool, error)
- func (db *PointDB) VirtualTerminalOutput(ctx context.Context, port uint32, data []byte) error
- func (db *PointDB) WriteDataSet(ds DataSet) error
- func (db *PointDB) WriteDescriptor(d Descriptor) error
- func (db *PointDB) WritePrototype(p Descriptor) error
- type PointRef
- type Primary
- type Reassembler
- type RejectedError
- type Secondary
- type Secret
- type SecurityEventEntry
- type SessionConfig
- type StatusElement
- type SymmetricAuthority
- type TimeAndInterval
- type TimeAndIntervalHandler
- type TimeSyncMode
- type UpdateKeyChange
- type UpdateKeyReply
- type UpdateKeyRequest
- type UserCertificate
- type UserRoleInfo
- type UserStatus
- type VirtualTerminalHandler
Examples ¶
Constants ¶
const ( ActivateOK = 0 ActivateBadObject = 1 ActivateBadConfig = 2 ActivateOtherError = 3 ActivateNotChecked = 4 )
Activate configuration status codes.
const ( AppFIR = 0x80 AppFIN = 0x40 AppCON = 0x20 AppUNS = 0x10 )
Application control bits; the low four bits are the sequence number.
const ( FCConfirm = 0 FCRead = 1 FCWrite = 2 FCSelect = 3 FCOperate = 4 FCDirectOperate = 5 FCDirectOperateNR = 6 FCImmedFreeze = 7 FCImmedFreezeNR = 8 FCFreezeClear = 9 FCFreezeClearNR = 10 FCFreezeAtTime = 11 FCFreezeAtTimeNR = 12 FCColdRestart = 13 FCWarmRestart = 14 FCInitializeData = 15 // obsolete FCInitializeAppl = 16 FCStartAppl = 17 FCStopAppl = 18 FCSaveConfig = 19 // deprecated FCEnableUnsolicited = 20 FCDisableUnsolicited = 21 FCAssignClass = 22 FCDelayMeasure = 23 FCRecordCurrentTime = 24 FCOpenFile = 25 FCCloseFile = 26 FCDeleteFile = 27 FCGetFileInfo = 28 FCAuthenticateFile = 29 FCAbortFile = 30 FCActivateConfig = 31 FCAuthRequest = 32 FCAuthRequestNoAck = 33 FCResponse = 129 FCUnsolicited = 130 FCAuthResponse = 131 )
Application function codes (4.2.2.5, Table 4-2). Requests use 0 to 128 (34 to 128 reserved), responses 129 to 255 (132 to 255 reserved).
const ( Q8StartStop = 0x00 Q16StartStop = 0x01 Q32StartStop = 0x02 QVAddr8 = 0x03 // virtual address ranges (group 102) QVAddr16 = 0x04 QVAddr32 = 0x05 QAll = 0x06 Q8Count = 0x07 Q16Count = 0x08 Q32Count = 0x09 Q8Index8 = 0x17 // 1-octet count, 1-octet index prefix Q8Index16 = 0x18 // 2-octet count, 1-octet index prefix Q8Index32 = 0x19 Q16Index8 = 0x27 Q16Index16 = 0x28 // 2-octet count, 2-octet index prefix Q16Index32 = 0x29 Q32Index8 = 0x37 Q32Index16 = 0x38 Q32Index32 = 0x39 QSize8 = 0x4B // 1-octet count, 1-octet object size prefix QFreeFormat = 0x5B // 1-octet count, 2-octet object size prefix QSize32 = 0x6B )
Object header qualifiers (4.2.2.7.3): bit 7 reserved (0), bits 6-4 the object prefix code, bits 3-0 the range specifier code. Every code of Table 4-6 is parsed.
const ( AttrVSTR = 1 // visible string AttrUINT = 2 // unsigned integer, 1–4 octets AttrINT = 3 // signed integer, 1–4 octets AttrFLT = 4 // IEEE-754 float, 4 or 8 octets AttrOSTR = 5 // octet string AttrBSTR = 6 // bit string // AttrList and AttrExtList are lists of UINT8-BSTR8 pairs (the list of // attribute variations, g0v255); an extended list is 256 octets plus // its length octet long (5.5.4.3, Table 5-16). AttrList = 254 AttrExtList = 255 )
Attribute data type codes decoded here.
const ( AuthChallenge = 1 AuthReply = 2 AuthAggressive = 3 AuthKeyStatusReq = 4 AuthKeyStatus = 5 AuthSessionKeyChg = 6 AuthErrorObj = 7 AuthUserCertificate = 8 AuthMACObj = 9 AuthUserStatusChange = 10 AuthUpdateKeyChgReq = 11 AuthUpdateKeyChgReply = 12 AuthUpdateKeyChg = 13 AuthUpdateKeyChgSig = 14 AuthUpdateKeyChgConf = 15 AuthReasonCritical = 1 KeyWrapAES128 = 1 KeyWrapAES256 = 2 KeyStatusOK = 1 KeyStatusNotInit = 2 KeyStatusCommFail = 3 KeyStatusAuthFail = 4 // UserUnknown and UserDefault are the reserved user numbers (Table 7-11). UserUnknown = 0 UserDefault = 1 )
Group 120 variations.
const ( AuthErrAuthFailed = 1 AuthErrUnexpectedResponse = 2 // SAv2 only AuthErrNoResponse = 3 // SAv2 only AuthErrAggressiveNotSupp = 4 AuthErrMACNotSupp = 5 AuthErrKeyWrapNotSupp = 6 AuthErrAuthorization = 7 AuthErrUpdateMethod = 8 AuthErrInvalidSignature = 9 AuthErrInvalidCertData = 10 AuthErrUnknownUser = 11 AuthErrMaxKeyStatus = 12 )
Authentication error codes (g120v7, A.45.7).
const ( StatUnexpected = iota StatAuthorizationFailures StatAuthFailures StatReplyTimeouts StatRekeysAuthFailure StatMessagesSent StatMessagesReceived StatCriticalSent StatCriticalReceived StatDiscarded StatErrorsSent StatErrorsReceived StatSuccessfulAuth StatSessionKeyChanges StatFailedSessionKeyChanges StatUpdateKeyChanges StatFailedUpdateKeyChanges StatRekeysRestart NumSecurityStatistics // 18 in this version (7.5.2.2) )
Security statistics (Table 7-6): the point indexes of g121/g122; the master keeps the same counters for its side of the association.
const ( MACSHA1Trunc4 = 1 MACSHA1Trunc10 = 2 MACSHA256Trunc8 = 3 MACSHA256Trunc16 = 4 MACSHA1Trunc8 = 5 MACAESGMAC = 6 )
MAC algorithm codes (g120 MAL) this implementation computes. Code 1 (HMAC-SHA-1 truncated to 4 octets) was SAv2 only and code 6 (AES-GMAC) is optional; neither is computed, so a challenge naming one fails.
const ( DescID = 1 DescUUID = 2 DescNSPC = 3 DescNAME = 4 DescDAEL = 5 DescPTYP = 6 DescCTLV = 7 DescCTLS = 8 )
Descriptor element codes (Table 5-7).
const ( DSNone = 0 DSVSTR = 1 DSUINT = 2 DSINT = 3 DSFLT = 4 DSOSTR = 5 DSBSTR = 6 DSTIME = 7 DSUNCD = 8 )
Data set data type codes (Table 5-6).
const ( DSReadable = 0x01 DSWritable = 0x02 DSStatic = 0x04 DSEvent = 0x08 DSByMaster = 0x10 )
Characteristics of a data set (g86v2): RD, WR, ST, EV, DF.
const ( SecEventBroadcastRefused = "dnp3_broadcast_refused" SecEventMaxAuthFailures = "dnp3_max_authentication_failures" SecEventMaxReplyTimeouts = "dnp3_max_reply_timeouts" SecEventMaxAuthRekeys = "dnp3_max_authentication_rekeys" SecEventMaxRekeysDueRestarts = "dnp3_max_rekeys_due_to_restarts" SecEventMaxErrorMessages = "dnp3_max_error_messages_sent" )
Security events of Secure Authentication that go to the application's security log (through SetAuditor) as well as the slog log: refused broadcasts, and the statistic limits of Table 7-6 when they act (7.5.2.2; IEEE 1815-2012 7.7.1 asks that dropping a connection be logged). No key material is ever included.
const ( FileModeNone = 0 // delete, get info FileModeRead = 1 FileModeWrite = 2 FileModeAppend = 3 )
File operational modes of a file command (g70v3).
const ( CtrlDIR = 0x80 // set on frames sent by a master CtrlPRM = 0x40 // set on primary (initiating) frames CtrlFCB = 0x20 CtrlFCV = 0x10 // DFC on secondary frames )
Link control octet bits.
const ( LinkResetLinkStates = 0 LinkTestLinkStates = 2 LinkConfirmedUserData = 3 LinkUnconfirmedUserData = 4 LinkRequestLinkStatus = 9 LinkAck = 0 LinkNack = 1 LinkStatus = 11 LinkNotSupported = 15 )
Link function codes. Primary codes are used with CtrlPRM, secondary codes without it.
const ( AddrMaxIndividual = 0xFFEF AddrSelf = 0xFFFC // self-address: optional, only as a destination AddrBroadcastNoConfirm = 0xFFFD // application confirmation not required to clear IIN1.0 AddrBroadcastMandatory = 0xFFFE // application confirmation mandatory to clear IIN1.0 AddrBroadcastOptional = 0xFFFF // application confirmation optional to clear IIN1.0 CtrlDFC = CtrlFCV // data flow control, secondary frames )
Special addresses (9.2.5.2, Table 9-3). Individual addresses are 0x0000 to 0xFFEF; 0xFFF0 to 0xFFFB are reserved and frames sent to them are discarded.
const ( OpNul = 0 OpPulseOn = 1 OpPulseOff = 2 OpLatchOn = 3 OpLatchOff = 4 TCCClose = 0x40 TCCTrip = 0x80 )
CROB operation types (low nibble of the control code) and trip/close codes (top two bits).
const ( PermRead = 0x124 PermWrite = 0x092 PermExec = 0x049 )
Permission bits of every class (owner, group, world: 5.3.2 keeps them equal).
const ( UnitsNoRepeat uint8 = 0 UnitsMilliseconds uint8 = 1 UnitsSeconds uint8 = 2 UnitsMinutes uint8 = 3 UnitsHours uint8 = 4 UnitsDays uint8 = 5 UnitsWeeks uint8 = 6 // Months on the same day of the month, the same weekday counted from // the start of the month, and the same weekday counted from its end. UnitsMonthsDay uint8 = 7 UnitsMonthsWeekday uint8 = 8 UnitsMonthsWeekdayEnd uint8 = 9 UnitsSeasons uint8 = 10 )
Units of a time-and-interval point (the codes of g50v4).
const ( TransportFIN = 0x80 TransportFIR = 0x40 )
Transport header bits.
const ( KeyChangeAES128SHA1 = 3 KeyChangeAES256SHA256 = 4 // the mandatory default KeyChangeAES256GMAC = 5 KeyChangeRSA1024SHA1 = 67 KeyChangeRSA2048SHA256 = 68 KeyChangeRSA3072SHA256 = 69 KeyChangeRSA2048GMAC = 70 KeyChangeRSA3072GMAC = 71 )
Update key change methods (Table 7-16). 0 to 2 and 64 to 66 are obsolete or unused.
const ( UserAdd = 1 UserDelete = 2 UserChange = 3 )
User status change operations (A.45.10).
const ( RoleViewer = 0 RoleOperator = 1 RoleEngineer = 2 RoleInstaller = 3 RoleSecAdm = 4 RoleSecAud = 5 RoleRBACMnt = 6 RoleSingleUser = 32768 )
User roles (Table 7-12).
const ( CertID = 1 CertAttribute = 2 )
Certificate types of g120v8.
const AttrAll = 254
AttrAll is the group 0 variation that reads every attribute.
const MaxLinkData = 250
MaxLinkData is the most user data one link frame carries.
const MaxSegment = MaxLinkData - 1
MaxSegment is the most application octets one transport segment carries.
Variables ¶
var ( ErrFileNotFound = errors.New("file not found") ErrFileDenied = errors.New("file access denied") )
ErrFileNotFound is returned by a FileStore for a name it does not hold, ErrFileDenied for one the requestor may not use.
var ( OIDIECUserRoles = asn1.ObjectIdentifier{1, 0, 62351, 8, 1} OIDIECUserRolesLegacy = asn1.ObjectIdentifier{1, 2, 840, 10070, 8, 1} )
OIDIECUserRoles is the IEC 62351-8:2020 access token OID (10.3), used when issuing; OIDIECUserRolesLegacy (IEC/TS 62351-8:2011) is accepted too (10.5.1.2).
var ErrAuthLimit = errors.New("secure authentication: max authentication rekeys exceeded; closing the connection")
ErrAuthLimit ends a session: the authentication failures passed Max Authentication Failures while rekeys due to them passed Max Authentication Rekeys (Table 7-8: close the TCP connection and log).
var ErrLinkCRC = errors.New("link frame CRC mismatch")
ErrLinkCRC is reported through LinkParser.Errors; it is exported for callers that decode single frames with DecodeFrame.
var ErrNoRoleAuthority = errors.New("no IEC 62351-8 role authority is configured to read user certificates")
ErrNoRoleAuthority refuses a g120v8 user certificate when no IEC 62351-8 role authority is configured to read its roles.
var ErrTimeout = errors.New("no response")
ErrTimeout is wrapped by errors for requests the outstation did not answer in time.
var OpenSerial = func(dev string, baud int, parity string) (io.ReadWriteCloser, error) { p, err := serial.Open(&serial.Config{Address: dev, BaudRate: baud, DataBits: 8, StopBits: 1, Parity: parity, Timeout: 200 * time.Millisecond}) if err != nil { return nil, err } return &lockedPort{p: p}, nil }
OpenSerial opens a serial line (8 data bits, 1 stop bit; parity "N", "E" or "O"). The master and the outstation's serial channel use it; tests, or an application that reaches its ports another way, replace it.
Functions ¶
func ActivateStatusName ¶
ActivateStatusName names an activate configuration status code.
func AppendAttribute ¶
AppendAttribute appends one group 0 object (header with the attribute set as a one-octet start-stop range, then type, length and value). A string value is sent as VSTR, a float64 with a fraction or outside the 32-bit range as FLT (8 octets), other numbers as UINT or INT in 4 octets, and []byte as OSTR.
func AppendAuthObject ¶
AppendAuthObject appends one group 120 object with the free-format qualifier (count 1, two-octet size) or, for g120v4, a count of one.
func AppendElements ¶
func AppendElements(out []byte, els []DescElement) []byte
AppendElements encodes descriptor elements.
func AppendHeader ¶
AppendHeader appends an object header. For start-stop and virtual address qualifiers a and b are the start and stop; for count, index- and size-prefix qualifiers a is the count; QAll takes neither.
func AppendKeyStatus ¶
AppendKeyStatus encodes g120v5 object data.
func AppendTime48 ¶
AppendTime48 appends t as a time48.
func AssignClass ¶
func AssignClass(sets []ClassAssignment) []byte
AssignClass builds the objects of an ASSIGN_CLASS request: per set a group 60 header with qualifier 0x06 (variation 1 for class 0, 2 to 4 for classes 1 to 3) followed by its point headers.
func AttributeName ¶
AttributeName is the key a group 0 variation is reported under.
func AuthErrorName ¶
AuthErrorName names an authentication error code.
func CRC ¶
CRC is the DNP3 link-layer CRC of b (initial value 0, complemented result). It is sent least significant octet first.
func CRCTableEntry ¶
CRCTableEntry is entry i of the CRC look-up table (Annex E).
func CTLSStatus ¶
CTLSStatus is the status code of a CTLS element (as in g12v1).
func CertifyStatus ¶
CertifyStatus is the symmetric certification data of a user status (Table A-10): the method's MAC of the status information with the authority certification key; for AES-GMAC the IV is the master's address, user number 0 (not yet assigned), the SCS and CSQ 0 (Table 7-21 row 10, F-593).
func ChallengeLen ¶
ChallengeLen is the challenge data size of a method (Table 7-17).
func ClassRequest ¶
ClassRequest is the object part of a READ (or unsolicited enable or disable) of the given classes, 0 to 3, with qualifier "all".
func ConfirmationMAC ¶
func ConfirmationMAC(method uint8, newKey []byte, receiver string, senderChal, receiverChal []byte, ksq uint32, usr uint16) ([]byte, error)
ConfirmationMAC is the g120v15 MAC (Table A-13): the receiver's name, the sender's then the receiver's challenge data, the KSQ and the user number, keyed with the new update key.
func ConfirmationMACIV ¶
func ConfirmationMACIV(method uint8, newKey, iv []byte, receiver string, senderChal, receiverChal []byte, ksq uint32, usr uint16) ([]byte, error)
ConfirmationMACIV is ConfirmationMAC with the AES-GMAC IV of the GMAC methods (Table 7-21: sender, user, last KSQ, last CSQ).
func CriticalMandatory ¶
CriticalMandatory lists the request function codes Table 7-7 marks mandatory critical; the master sends these in aggressive mode.
func DSASign ¶
DSASign signs data with the method's hash (SHA-1 for 67, SHA-256 otherwise), DER encoded.
func DataSetType ¶
DataSetType maps a data type name (vstr, uint, ...) to its code.
func DataSetValue ¶
DataSetValue decodes one element value by its data type.
func EncodeBlock ¶
EncodeBlock encodes an object header and its objects. Start-stop qualifiers need consecutive indices; relative-time objects (g2v3, g4v3) take their offset from the preceding CTO given as cto.
Example ¶
Encoding an object block and reading it back.
package main
import (
"fmt"
"github.com/cB-Sigma/dnp3"
)
func main() {
b, _ := dnp3.EncodeBlock(30, 2, dnp3.Q8StartStop, []dnp3.Point{{Index: 3, Value: 1234.0, Flags: 0x01}})
fmt.Printf("% X\n", b)
blocks, _ := dnp3.ParseObjects(b, true)
fmt.Println(blocks[0].Points[0].Value)
}
Output: 1E 02 00 03 03 01 D2 04 1234
func EncodeDataSetValue ¶
func EncodeDataSetValue(e DescElement, v any) ([]byte, error)
EncodeDataSetValue encodes a value for an element (maximum length and type from the descriptor): strings for VSTR/UNCD, hex strings for OSTR and BSTR, numbers for UINT/INT/FLT, time.Time or RFC 3339 for TIME.
func EncodePointRefs ¶
EncodePointRefs is a g86v3 object's data.
func Family ¶
Family is the point type a group reports: binary, double, binary-output, counter, frozen-counter, analog or analog-output; empty for groups that are not data points.
func FilePath ¶
FilePath turns a request's file name into a store path: "\" and "/" both separate segments; "." and ".." are refused.
func GMACMethod ¶
GMACMethod reports the methods authenticating with AES-GMAC (5, 70, 71).
func IsBroadcast ¶
IsBroadcast reports the three broadcast addresses (9.2.5.2.1).
func IsReservedAddress ¶
IsReservedAddress reports 0xFFF0 to 0xFFFB, which no frame may be passed up for (9.2.5.2.3).
func IssueDSAUserCertificate ¶
func IssueDSAUserCertificate(method uint8, key *dsa.PrivateKey, issuer string, user string, spki []byte, roles []UserRoleInfo, notBefore, notAfter time.Time) ([]byte, error)
IssueDSAUserCertificate issues an ID certificate for user (public key SubjectPublicKeyInfo spki) with the given roles, signed with the authority's DSA key (SHA-1 for method 67, SHA-256 otherwise).
func MACByName ¶
MACByName is the MAC algorithm code of a name: hmac-sha256-16, hmac-sha256-8, hmac-sha1-10, hmac-sha1-8 or aes-gmac; 0 for any other.
func MarshalDSAPublicKey ¶
MarshalDSAPublicKey encodes a DSA public key as an X.509 SubjectPublicKeyInfo (RFC 3279 2.3.2), the form a g120v10 carries (A.45.10); the standard library parses but does not write it.
func MethodHash ¶
MethodHash is the hash of a method (its HMAC, or the digest its DSA signatures use) and the update key length.
func NoResponse ¶
NoResponse reports the request function codes the outstation never answers (the _NR variants and AUTH_REQUEST_NO_ACK), plus CONFIRM.
func ObjectSize ¶
ObjectSize is the octets per object of a fixed-size, non-packed variation (0 for packed, free-format and unknown ones).
func PackedBits ¶
PackedBits is the bits per point of a packed variation (0 otherwise).
func ParseAuthObject ¶
ParseAuthObject returns the variation and object data of the first group 120 object in a fragment's objects.
func ParseSessionKeyData ¶
ParseSessionKeyData splits unwrapped g120v6 key data; keyStatus is the key status data the master claims to answer (padding included).
func PointGroup ¶
Point types an outstation serves: the static group and the event group. PointGroup is the static and event group of a point type ("binary", "analog", ...; the keys of the outstation database's point types).
func PointTypeOf ¶
PointTypeOf is the point type of a static or event group.
func Segment ¶
Segment splits an application fragment into transport segments of 1 to 249 application octets (8.2.2). seq is the sender's running sequence number and is advanced per segment.
func SelfSignedDSAAuthority ¶
func SelfSignedDSAAuthority(key *dsa.PrivateKey, name string, notBefore, notAfter time.Time) ([]byte, error)
SelfSignedDSAAuthority is an authority certificate for a DSA key (for configuring the outstation's trust in a DSA authority).
func SerialParams ¶
SerialParams reads a serial URL (serial:///dev/ttyS1?baud=9600&parity=N): the device, the baud rate and the parity letter.
func SessionKeyData ¶
SessionKeyData is the plaintext wrapped in a g120v6: the key length, the control and monitoring direction session keys and the key status object data being answered, zero-padded to a multiple of 8 octets.
func SetAuditor ¶
SetAuditor sets where Secure Authentication security events are recorded for the whole process (an application's security log); nil stops recording.
func SignatureData ¶
func SignatureData(outstation string, masterChal, ostnChal []byte, ksq uint32, usr uint16, encrypted []byte) []byte
SignatureData is what the user's g120v14 signature covers (Table A-12).
func SplitAggressive ¶
SplitAggressive finds an aggressive-mode fragment's parts: the g120v3 object data, the objects between, the MAC and the length of the fragment objects before the MAC value. ok is false when the objects do not start with g120v3 and end with g120v9.
func StatisticName ¶
StatisticName names a security statistic by its index (modulo 18, as further associations report in blocks of 18).
func StatusName ¶
StatusName is the readable name of a command status code.
func UpdateKeyData ¶
UpdateKeyData is the plaintext of the encrypted update key data (Table A-11), zero-padded to a multiple of 8 octets when pad is set.
func ValidQualifier ¶
ValidQualifier reports the codes of Table 4-6.
Types ¶
type ActivateStatus ¶
type ActivateStatus struct {
Delay time.Duration
Elements []StatusElement
}
ActivateStatus is a g91v1.
func ParseActivateStatus ¶
func ParseActivateStatus(b []byte) (ActivateStatus, error)
ParseActivateStatus decodes a g91v1.
type Association ¶
type Association struct {
// contains filtered or unexported fields
}
Association is the outstation's side of one master–outstation association.
func NewAssociation ¶
func NewAssociation(cfg OutstationConfig) *Association
NewAssociation makes an association (Run starts it).
Example ¶
An outstation: a point database, one association per master, served over TCP; a change becomes a class 1 event.
package main
import (
"context"
"fmt"
"net"
"time"
"github.com/cB-Sigma/dnp3"
)
// exampleHandler is an outstation application that accepts every control
// and supports nothing else.
type exampleHandler struct{}
func (exampleHandler) Control(context.Context, dnp3.ControlRequest) uint8 { return 0 }
func (exampleHandler) DataSetControl(context.Context, dnp3.DataSetControl) uint8 { return 4 }
func (exampleHandler) Restart(context.Context, bool) time.Duration { return 0 }
func (exampleHandler) Activate(context.Context, [][]byte) dnp3.ActivateStatus {
return dnp3.ActivateStatus{}
}
func (exampleHandler) Application(context.Context, byte, [][]byte) dnp3.IIN {
return dnp3.IINNoFuncCodeSupport
}
func (exampleHandler) TimeSet(time.Time) {}
func (exampleHandler) DataSetWritten(context.Context, dnp3.DataSet) {}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
db := dnp3.NewPointDB()
_ = db.Define(dnp3.DBPoint{Type: "binary", Index: 0, Class0: true, Class: 1})
_, _ = db.Update(ctx, "binary", 0, 0, nil, 0x01, time.Now())
a := dnp3.NewAssociation(dnp3.OutstationConfig{Address: 10, Master: 1, DB: db, Handler: exampleHandler{}})
n := &dnp3.OutstationNet{}
n.Add(a)
go a.Run(ctx)
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
panic(err)
}
defer ln.Close()
go func() {
for {
c, err := ln.Accept()
if err != nil {
return
}
go n.ServeStream(ctx, c)
}
}()
m, err := dnp3.Dial(ctx, dnp3.MasterConfig{URL: "tcp://" + ln.Addr().String(), MasterAddress: 1, OutstationAddress: 10, Timeout: 2 * time.Second})
if err != nil {
panic(err)
}
defer m.Close()
_, _ = db.Update(ctx, "binary", 0, 1, nil, 0x01, time.Now())
frags, err := m.Request(ctx, dnp3.FCRead, dnp3.ClassRequest(1))
if err != nil {
panic(err)
}
blocks, _ := dnp3.ParseObjects(frags[0].Objects, true)
p := blocks[0].Points[0]
fmt.Printf("event g%dv%d index %d: %v\n", p.Group, p.Var, p.Index, p.Value)
}
Output: event g2v2 index 0: true
func (*Association) Accepts ¶
func (a *Association) Accepts(dest uint16) bool
Accepts reports whether the association takes a frame to dest.
func (*Association) Attach ¶
func (a *Association) Attach(l OutLink)
Attach makes l the link the association sends on (a new connection).
func (*Association) Deliver ¶
func (a *Association) Deliver(f Frame)
Deliver takes a primary frame from the association's master: the secondary station rules, the transport function, then the request.
func (*Association) Detach ¶
func (a *Association) Detach(l OutLink)
Detach forgets l when it is the current link.
func (*Association) Idle ¶
func (a *Association) Idle() time.Duration
Idle is how long nothing was received.
func (*Association) KeepAlive ¶
func (a *Association) KeepAlive()
KeepAlive sends REQUEST_LINK_STATUS on the link (13.2.3.3.1).
func (*Association) Linked ¶
func (a *Association) Linked() bool
Linked reports whether a link is attached.
func (*Association) Master ¶
func (a *Association) Master() uint16
Master is the association's master address.
func (*Association) Run ¶
func (a *Association) Run(ctx context.Context)
Run serves the association until ctx ends.
func (*Association) Status ¶
func (a *Association) Status() map[string]any
Status is a summary for the status container.
func (*Association) String ¶
func (a *Association) String() string
String names the association for logs.
type AsymmetricAuthority ¶
type AsymmetricAuthority struct {
KeyChangeMethod uint8
Key *dsa.PrivateKey
}
AsymmetricAuthority certifies user status changes with its DSA private key (methods 67 to 69).
func (AsymmetricAuthority) Certify ¶
func (a AsymmetricAuthority) Certify(u UserStatus) ([]byte, error)
Certify signs the status information.
func (AsymmetricAuthority) EncryptUpdateKey ¶
EncryptUpdateKey is not used with asymmetric methods.
func (AsymmetricAuthority) Method ¶
func (a AsymmetricAuthority) Method() uint8
Method is the key change method.
type Auth ¶
type Auth struct {
User uint16
UpdateKey []byte // AES-128 or AES-256 key
MAL uint8 // MAC algorithm for the master's own challenges
Aggressive bool
// ChallengeResponses challenges responses with objects (see AuthConfig).
ChallengeResponses bool
// KeyChangeCount is the authentication message count after which the
// session keys are changed (0: never by count).
KeyChangeCount int
// Subject and Tenant name the association in security events.
Subject, Tenant string
// contains filtered or unexported fields
}
Auth is a master's Secure Authentication state for one association.
func NewAuth ¶
func NewAuth(c *AuthConfig) (*Auth, error)
NewAuth builds a master's Secure Authentication state (nil for a nil configuration).
func (*Auth) KeyChangeDue ¶
KeyChangeDue reports that the authentication message count since the last session key change reached KeyChangeCount.
func (*Auth) RestartRekey ¶
RestartRekey reports whether the master is to change the session keys because the outstation restarted (Table 7-8, master only): not once Rekeys Due to Restarts passed Max Rekeys Due to Restarts, until the next key change for the interval.
func (*Auth) ScheduledKeyChange ¶
func (a *Auth) ScheduledKeyChange()
ScheduledKeyChange notes a session key change for the interval or the message count: rekeys due to authentication failures and restarts resume and Max Authentication Rekeys is reset (Table 7-8).
func (*Auth) SetUpdateKey ¶
SetUpdateKey replaces the update key and user number, for an application that stored a changed update key and restores it.
func (*Auth) Statistics ¶
Statistics is a copy of the master's security statistics (Table 7-6).
func (*Auth) UpdateKeyOf ¶
UpdateKeyOf returns the user's current update key and user number (after a change-update-key, the new ones).
type AuthConfig ¶
type AuthConfig struct {
// User is the user number (Table 7-11); 0 is taken as the default
// user 1.
User uint16
// UpdateKey is the user's update key: 16 octets (AES-128 key wrap) or
// 32 (AES-256 key wrap).
UpdateKey []byte
// MAC is the MAC algorithm (one of the MAC constants) of the master's
// own challenges; 0 is HMAC-SHA-256 truncated to 16 octets. MACByName
// reads the usual names.
MAC uint8
// AggressiveMode sends the critical requests of Table 7-7 with their
// authentication (g120v3 ... g120v9) once a challenge has been
// answered since the last session key change (7.5.3.3).
AggressiveMode bool
// ChallengeResponses has the master challenge every solicited and
// unsolicited response that carries objects before using it
// (7.5.2.3.2 c).
ChallengeResponses bool
// KeyChangeCount changes the session keys after this many
// authentication messages in either direction (7.6.1.4.4); 0: never
// by count.
KeyChangeCount int
// The statistic thresholds that act as moving limits (7.5.2.2, Table
// 7-15); 0 takes the defaults of Table 7-6: 5, 3, 3 and 3.
MaxAuthenticationFailures int
MaxReplyTimeouts int
MaxAuthenticationRekeys int
MaxRekeysDueToRestarts int
}
AuthConfig enables Secure Authentication v5 on a master association.
type Authority ¶
type Authority interface {
Method() uint8
// Certify returns the certification data of a user status change.
Certify(u UserStatus) ([]byte, error)
// EncryptUpdateKey returns the encrypted update key data (symmetric
// methods only).
EncryptUpdateKey(name string, key, ostnChallenge []byte) ([]byte, error)
}
Authority is the key distribution authority as the master sees it (7.5.4.5): it certifies user status changes and, for the symmetric methods, encrypts new update keys for the outstation. The standard keeps it apart from the master and leaves the master–authority protocol open.
type Block ¶
Block is an object header and its decoded objects.
func ParseObjects ¶
ParseObjects decodes the object headers and objects of a fragment. With withData false (READ requests and unsolicited enable/disable) headers carry no objects. An unknown group/variation stops parsing, since its size is unknown; the blocks decoded so far are returned with the error.
type CertifiedUser ¶
type CertifiedUser struct {
Name string
PublicKey any // ID certificates
Roles []UserRoleInfo
NotBefore time.Time
NotAfter time.Time
// Token is the IEC 62351-8 access token as the role authority read it
// (its signature checked by VerifyUserCertificate).
Token iotsec.AccessToken
}
CertifiedUser is what a verified user certificate says.
func VerifyUserCertificate ¶
func VerifyUserCertificate(u UserCertificate, authority *x509.Certificate, ra iotsec.RoleAuthority) (CertifiedUser, error)
VerifyUserCertificate checks a g120v8 certificate against the authority certificate and returns what it certifies; ra reads the IEC 62351-8 access token (and checks the signature of attribute certificates that are not DSA-signed).
func (CertifiedUser) Role ¶
func (c CertifiedUser) Role(ra iotsec.RoleAuthority, aors []string) (UserRoleInfo, bool)
Role is the first role of the first entry whose area of responsibility applies to an outstation with the areas aors (remote access), as ra matches areas (IEC 62351-8 10.4.4.9), or false.
type Challenge ¶
Challenge is a decoded g120v1.
func ParseChallenge ¶
ParseChallenge decodes g120v1 object data (at least 4 octets of challenge data, A.45.1).
type Channel ¶
type Channel struct {
// contains filtered or unexported fields
}
Channel is one shared connection.
func OpenChannel ¶
func OpenChannel(ctx context.Context, cfg MasterConfig) (*Channel, error)
OpenChannel opens the connection of cfg (URL, TLS, Timeout) for several masters.
func (*Channel) Attach ¶
func (c *Channel) Attach(cfg MasterConfig) (*Master, error)
Attach adds an association for cfg.OutstationAddress (its own addresses, timeouts, authentication; the URL and TLS are the channel's).
type ClassAssignment ¶
ClassAssignment is one assignment set of an ASSIGN_CLASS request (4.4.14): the class (0 disables events, 1 to 3) and the object headers of the points whose events it takes.
type ClassScan ¶ added in v0.2.0
ClassScan polls event classes (1 to 3; 0 for static data) every Period.
type ControlRequest ¶
type ControlRequest struct {
Func byte
Group uint8
Var uint8
Index uint32
CROB CROB
Value float64
Select bool // a SELECT: check only, do not operate
User uint16 // the authenticated user (Secure Authentication), 0 without
}
ControlRequest is one control object of a SELECT, OPERATE or DIRECT_OPERATE(_NR): a CROB (g12v1) or an analog output block (g41).
type DBPoint ¶
type DBPoint struct {
Type string
Index uint32
Value float64
Raw []byte // octet strings
Flags uint8
Time time.Time
Class0 bool // reported in class 0 polls
Class int // event class 1 to 3, 0: no events
StaticVar uint8 // 0: the type's default
EventVar uint8 // 0: the type's default
Deadband float64 // analogs, counters: an event needs a change larger than this
Frozen float64 // counters: the value at the last freeze
// Units is the interval's units code of a time-and-interval point
// (whose Time is its start and Value its interval count).
Units uint8
// contains filtered or unexported fields
}
DBPoint is one point of the outstation database.
type DataSet ¶
DataSet is a g87v1 (present value) or g88v1 (event) object: identifier, evaluation or event time and the raw element values.
func ParseDataSet ¶
ParseDataSet decodes a g87v1 or g88v1.
type DataSetControl ¶
type DataSetControl struct {
Func byte
Select bool
ID uint32
Names []string
Values []any
User uint16
}
DataSetControl is a control group of a data set in a control request (5.4.11): the values of the CTLV elements following one CTLS.
type DataSetDef ¶
type DataSetDef struct {
Desc Descriptor
Chars uint8 // DSReadable, DSWritable, DSStatic, DSEvent, DSByMaster
Refs []PointRef
Class int // event class of its events (0: none)
Class0 bool // present value included in class 0
Values [][]byte
Time time.Time
Received bool // a value was written by the master
}
DataSetDef is one data set of the outstation.
type DescElement ¶
DescElement is one descriptor element.
func IDElement ¶
func IDElement(id uint32) DescElement
IDElement is the mandatory first element carrying the identifier (a 2-octet UINT up to 65535, as in EX 5-5).
func ParseElements ¶
func ParseElements(b []byte) ([]DescElement, error)
ParseElements decodes descriptor elements.
func (DescElement) Name ¶
func (e DescElement) Name() string
Name is the element's name (the ancillary VSTR of DAEL, CTLV, CTLS and NAME; the instance name after the UUID of a PTYP).
type Descriptor ¶
type Descriptor struct {
ID uint32
UUID [16]byte // prototypes only
Namespace string // prototypes only
Name string
Elements []DescElement // after the ID (and UUID, NSPC, NAME)
}
Descriptor is a data set descriptor (g86v1) or prototype (g85v1).
func ParseDescriptor ¶
func ParseDescriptor(b []byte, proto bool) (Descriptor, error)
ParseDescriptor decodes a g86v1 (proto false) or g85v1 (proto true) and checks the element order rules (5.4.6.2, 5.4.7.2).
func (Descriptor) EncodeDescriptor ¶
func (d Descriptor) EncodeDescriptor() []byte
EncodeDescriptor is a g86v1 object's data.
func (Descriptor) EncodePrototype ¶
func (d Descriptor) EncodePrototype() []byte
EncodePrototype is a g85v1 object's data.
func (Descriptor) Flatten ¶
func (d Descriptor) Flatten(protos map[[16]byte]Descriptor) ([]DescElement, error)
Flatten resolves the data elements of a descriptor, substituting each prototype reference with the prototype's elements (5.4.6.2.5).
type Event ¶
type Event struct {
ID int64 `json:"id"`
Class int `json:"class"`
Group uint8 `json:"g"`
Var uint8 `json:"v"`
Index uint32 `json:"i"`
Value float64 `json:"value"`
Raw []byte `json:"raw,omitempty"`
Flags uint8 `json:"flags"`
Time time.Time `json:"t"`
Assoc uint16 `json:"assoc,omitempty"`
}
Event is one buffered event.
type EventBuffer ¶
type EventBuffer struct {
// contains filtered or unexported fields
}
EventBuffer is an association's events per class, bounded (4.5.12).
func NewEventBuffer ¶
func NewEventBuffer(capacity map[int]int, store EventStore) *EventBuffer
NewEventBuffer makes a buffer with per-class capacities (0: 100 each).
func (*EventBuffer) Add ¶
func (b *EventBuffer) Add(ctx context.Context, e Event)
Add buffers an event; a full class loses the event and sets overflow.
func (*EventBuffer) Capacity ¶
func (b *EventBuffer) Capacity(class int) int
Capacity is a class's buffer size.
func (*EventBuffer) Classes ¶
func (b *EventBuffer) Classes(except map[int64]bool) map[int]bool
Classes reports which classes have events not in except.
func (*EventBuffer) Counts ¶
func (b *EventBuffer) Counts() map[int]int
Len is the number of buffered events. Counts are the buffered events per class.
func (*EventBuffer) Len ¶
func (b *EventBuffer) Len() int
Len counts the buffered events of every class.
func (*EventBuffer) Load ¶
func (b *EventBuffer) Load(ctx context.Context) error
Load restores the durable events.
func (*EventBuffer) Overflow ¶
func (b *EventBuffer) Overflow() bool
Overflow reports the overflow condition: set by a lost event, cleared once every class has room again.
type EventStore ¶
type EventStore interface {
Add(ctx context.Context, payload []byte) (int64, error)
Delete(ctx context.Context, ids ...int64) error
ListPayloads(ctx context.Context) ([]int64, [][]byte, error)
}
EventStore keeps an association's events durably (an application backs it with its own queue or database); nil keeps them in memory only.
type FileAuth ¶
FileAuth is g70v2: a request for (and the answer with) a file authentication key.
func ParseFileAuth ¶
ParseFileAuth decodes g70v2 object data.
type FileClient ¶
type FileClient struct {
M *Master
MaxBlock uint16 // largest block accepted; default 1024
Wait time.Duration // how long to poll for a delayed answer; default 10 s
Other func(Fragment)
User string // with Password: AUTHENTICATE_FILE before open and delete
Password string
// contains filtered or unexported fields
}
FileClient runs the master's side of sequential file transfer (5.3) on an association. Objects the outstation returns later as events are collected by polling classes 1 to 3; Other receives every fragment of those polls so their other data is not lost.
func (*FileClient) Delete ¶
func (c *FileClient) Delete(ctx context.Context, name string) error
Delete removes a file.
func (*FileClient) Info ¶
func (c *FileClient) Info(ctx context.Context, name string) (FileDescriptor, error)
Info returns a file's descriptor (GET_FILE_INFO).
func (*FileClient) List ¶
func (c *FileClient) List(ctx context.Context, dir string) ([]FileDescriptor, error)
List reads a directory file into its entries.
type FileCommand ¶
type FileCommand struct {
Created time.Time
Permissions uint16
AuthKey uint32
Size uint32
Mode uint16
MaxBlock uint16
RequestID uint16
Name string
}
FileCommand is g70v3: open or delete a file.
func ParseFileCommand ¶
func ParseFileCommand(b []byte) (FileCommand, error)
ParseFileCommand decodes g70v3 object data.
func (FileCommand) Encode ¶
func (c FileCommand) Encode() []byte
Encode is the object data (the name follows the fixed fields).
type FileDescriptor ¶
type FileDescriptor struct {
Type uint16
Size uint32
Created time.Time
Permissions uint16
RequestID uint16
Name string
}
FileDescriptor is g70v7: file information (GET_FILE_INFO, directory entries). Type 0 is a directory, 1 a simple file.
func ParseDirectory ¶
func ParseDirectory(b []byte) ([]FileDescriptor, error)
ParseDirectory splits the content of a directory file into its g70v7 entries (5.3: each entry is a descriptor preceded by nothing; the descriptors follow each other).
func ParseFileDescriptor ¶
func ParseFileDescriptor(b []byte) (FileDescriptor, error)
ParseFileDescriptor decodes g70v7 object data.
type FileInfo ¶
type FileInfo struct {
Name string // base name
Dir bool
Size uint32
Created time.Time
Permissions uint16
}
FileInfo describes a file or directory. Size is the length of a file, or the number of entries of a directory (5.3.5).
type FileRights ¶
type FileRights struct{ Read, Write bool }
FileRights are the rights of a request without a valid key.
type FileStatus ¶
type FileStatus struct {
Handle uint32
Size uint32
MaxBlock uint16
RequestID uint16
Status uint8
Text string
}
FileStatus is g70v4: the answer to open, close, delete and abort, and the request of close and abort.
func ParseFileStatus ¶
func ParseFileStatus(b []byte) (FileStatus, error)
ParseFileStatus decodes g70v4 object data.
type FileStore ¶
type FileStore interface {
Stat(ctx context.Context, path string) (FileInfo, error)
List(ctx context.Context, dir string) ([]FileInfo, error)
Read(ctx context.Context, path string) ([]byte, error)
Write(ctx context.Context, path string, data []byte, created time.Time, perms uint16) error
Delete(ctx context.Context, path string) error
}
FileStore holds an outstation's files. Paths are the file name of the request without separators at either end, segments joined by "/" ("" is the root directory).
type FileTransport ¶
FileTransport is g70v5: a block of file data. Block numbers start at 0; Last marks the final block (bit 31 of the block field).
func ParseFileTransport ¶
func ParseFileTransport(b []byte) (FileTransport, error)
ParseFileTransport decodes g70v5 object data.
type FileTransportStatus ¶
FileTransportStatus is g70v6: the status of a file data transfer.
func ParseFileTransportStatus ¶
func ParseFileTransportStatus(b []byte) (FileTransportStatus, error)
ParseFileTransportStatus decodes g70v6 object data.
func (FileTransportStatus) Encode ¶
func (t FileTransportStatus) Encode() []byte
Encode is the object data.
type FileUser ¶
FileUser is a user of AUTHENTICATE_FILE: files are readable, and writable and deletable with Write.
type Fragment ¶
Fragment is one application fragment (request or response).
func ParseFragment ¶
ParseFragment decodes an application fragment's header.
func (Fragment) IsResponse ¶
IsResponse reports a solicited or unsolicited response.
type Frame ¶
Frame is one link-layer frame.
func DecodeFrame ¶
DecodeFrame decodes exactly one encoded frame.
func (Frame) FCB ¶
FCB reports the frame count bit and FCV the frame count valid bit of a primary frame.
type Handler ¶
type Handler interface {
// Control returns the control status (0 success; codes of Table 11-7).
Control(ctx context.Context, c ControlRequest) uint8
// DataSetControl issues one control group of a data set.
DataSetControl(ctx context.Context, c DataSetControl) uint8
// Restart returns the time the outstation will be busy (4.4.9).
Restart(ctx context.Context, cold bool) time.Duration
// Activate checks and activates the configurations named by the
// request objects (g70v8 file specifications, g110 octet strings).
Activate(ctx context.Context, names [][]byte) ActivateStatus
// Application initialises, starts or stops applications (g90 names;
// nil for all); a non-zero IIN (2.0, 2.1, 2.4) reports a refusal.
Application(ctx context.Context, fc byte, names [][]byte) IIN
// TimeSet reports a time synchronisation: the master's time now.
TimeSet(masterNow time.Time)
// DataSetWritten reports a data set written by the master.
DataSetWritten(ctx context.Context, ds DataSet)
}
Handler performs what the outstation cannot do from its database.
type Header ¶
type Header struct {
Group, Var, Qual uint8
Start, Stop uint32 // start-stop and virtual address qualifiers
Count uint32 // number of objects that follow
}
Header is one object header.
type IIN ¶
type IIN uint16
IIN is the internal indications of a response: IIN1 in the low octet, IIN2 in the high octet.
const ( IINBroadcast IIN = 1 << 0 IINClass1Events IIN = 1 << 1 IINClass2Events IIN = 1 << 2 IINClass3Events IIN = 1 << 3 IINNeedTime IIN = 1 << 4 IINLocalControl IIN = 1 << 5 IINDeviceTrouble IIN = 1 << 6 IINDeviceRestart IIN = 1 << 7 IINNoFuncCodeSupport IIN = 1 << 8 IINObjectUnknown IIN = 1 << 9 IINParameterError IIN = 1 << 10 IINEventBufferOverflow IIN = 1 << 11 IINAlreadyExecuting IIN = 1 << 12 IINConfigCorrupt IIN = 1 << 13 IINReserved2 IIN = 1 << 14 // IIN2.6, always 0 IINReserved1 IIN = 1 << 15 // IIN2.7, always 0 IINClassEvents = IINClass1Events | IINClass2Events | IINClass3Events )
Internal indication bits.
type KeyStatus ¶
type KeyStatus struct {
KSQ uint32
User uint16
KeyWrap uint8
Status uint8
MAL uint8
Challenge []byte
MAC []byte
}
KeyStatus is a decoded g120v5.
func ParseKeyStatus ¶
ParseKeyStatus decodes g120v5 object data.
func (KeyStatus) Unauthenticated ¶
Unauthenticated is the key status object data without its MAC: what the key wrap data carries (A.45.6 Table A-5).
type LinkAction ¶
LinkAction is what a secondary station does with a received primary frame: the secondary function code to answer with (when Respond), and whether the user data goes to the transport function (Deliver).
type LinkParser ¶
type LinkParser struct {
// Errors counts discarded octets runs (garbage, bad CRC, bad length).
Errors int
// contains filtered or unexported fields
}
LinkParser extracts frames from a byte stream. It tolerates reads split anywhere and resynchronises on the start octets after garbage or a CRC error.
func (*LinkParser) Feed ¶
func (p *LinkParser) Feed(b []byte) []Frame
Feed adds received octets and returns every complete frame.
type Master ¶
type Master struct {
// contains filtered or unexported fields
}
Master is a connected association: one outstanding request at a time, with unsolicited responses confirmed and handed to OnUnsolicited.
func Dial ¶
func Dial(ctx context.Context, cfg MasterConfig) (*Master, error)
Dial connects to an outstation.
func (*Master) ChangeSessionKeys ¶
ChangeSessionKeys sets new session keys: key status request, then a session key change answering the key status, then a check of the MAC in the outstation's new key status (A.45.5 Table A-4: over the whole session key change fragment, with the new monitoring direction key).
func (*Master) ChangeUpdateKey ¶
func (m *Master) ChangeUpdateKey(ctx context.Context, c UpdateKeyChange) error
ChangeUpdateKey runs the user status change and update key change and, when they succeed, makes the new update key and user number current and changes the session keys with them. Delete stops after the status change.
func (*Master) Done ¶
func (m *Master) Done() <-chan struct{}
Done is closed when the connection ends.
func (*Master) LearnedAddress ¶
LearnedAddress is the outstation's own address, learnt from its answer to the self-address (false before one arrived).
func (*Master) Quiet ¶
Quiet keeps requests back for d (the delay a restarting outstation announced, 4.4.9).
func (*Master) Request ¶
Request sends one request and returns every fragment of its response, confirming fragments that ask for it. A response whose IIN2 reports the request as unsupported or malformed returns a *RejectedError with the fragments.
func (*Master) RunSession ¶ added in v0.2.0
func (m *Master) RunSession(ctx context.Context, cfg SessionConfig) error
RunSession polls the outstation as cfg says until ctx is done (it returns ctx's error) or the connection ends (it returns why).
func (*Master) SelectOperate ¶
func (m *Master) SelectOperate(ctx context.Context, objects []byte, within time.Duration, check func(fc byte, frags []Fragment) error) error
SelectOperate sends SELECT and then OPERATE with the same objects as consecutive requests (no other request in between). check validates each response (nil accepts any); the operate is not sent when the select fails or took longer than within.
func (*Master) SyncTime ¶ added in v0.2.0
SyncTime sets the outstation's clock by the non-LAN procedure (DELAY_MEASURE, then a WRITE of g50v1 corrected by half the round trip less the outstation's processing delay) or the LAN one (RECORD_CURRENT_TIME, then a WRITE of g50v3 with the time it was sent).
type MasterConfig ¶
type MasterConfig struct {
URL string // tcp://host:port or udp://host:port
MasterAddress uint16
OutstationAddress uint16
Timeout time.Duration // response timeout per fragment
Log *slog.Logger
// OnUnsolicited is called from the receive loop with every unsolicited
// response (already confirmed when it asked for confirmation).
OnUnsolicited func(Fragment)
// Auth enables Secure Authentication: challenges of critical requests
// are answered and ChangeSessionKeys sets the session keys.
Auth *Auth
// KeepAlive, on tcp URLs, sends REQUEST_LINK_STATUS when nothing was
// received for this long and ends the connection when nothing answers
// within Timeout (13.2.3.3.1). 0 disables it.
KeepAlive time.Duration
// LinkConfirm sends requests as CONFIRMED_USER_DATA, resetting the
// outstation's link first and retrying each frame LinkRetries times
// (9.2.6.1, 9.2.6.3); application confirmations stay unconfirmed.
LinkConfirm bool
LinkRetries int
// MaxRequest is the largest request fragment sent (4.3 rule 4); 0 is
// 2048. A larger request fails before it is sent.
MaxRequest int
// TLS, for tcp URLs, runs the connection under a TLS profile, for
// example the IEC 62351-3 profile with mutual certificates (IEEE
// 1815-2012 7.4 points to it). A profile that renews keys on the
// connection may end a connection whose peer does not take part; the
// caller reconnects. When the connection implements
// iotsec.KeepaliveConn the master registers REQUEST_LINK_STATUS as
// its keepalive.
TLS iotsec.TLSClient
// Dialer opens tcp connections (nil: a net.Dialer). UDP uses an
// unconnected socket of its own (see udppeer.go) and serial lines no
// dialer.
Dialer iotsec.Dialer
// LocalPort, for udp URLs, is the local port to send from and listen
// on (0: any); see udpPeer.
LocalPort int
}
MasterConfig configures one master–outstation association.
type OutstationAuth ¶
type OutstationAuth struct {
// contains filtered or unexported fields
}
OutstationAuth is the Secure Authentication state of one association.
func NewOutstationAuth ¶
func NewOutstationAuth(c OutstationAuthConfig) (*OutstationAuth, error)
NewOutstationAuth checks the settings.
func (*OutstationAuth) RecentSecurityEvents ¶
func (a *OutstationAuth) RecentSecurityEvents() ([]SecurityEventEntry, uint64)
RecentSecurityEvents returns the kept security events, newest first, and the number of broadcasts refused since start.
func (*OutstationAuth) SAState ¶
func (a *OutstationAuth) SAState() (string, time.Time)
SAState describes the association's Secure Authentication exchange: "wait-for-reply" while a challenge of ours is unanswered, "wait-for-key-change" while an update key change is in progress, else "idle"; and the time the session keys last changed (zero if never).
func (*OutstationAuth) SetRSAKey ¶
func (a *OutstationAuth) SetRSAKey(k *rsa.PrivateKey)
Users is a copy of the users (for status and persistence). SetRSAKey replaces the outstation's key transport key (a renewed certificate's key, IEC 62351-9 7.6).
func (*OutstationAuth) Statistics ¶
func (a *OutstationAuth) Statistics() [NumSecurityStatistics]uint32
Statistics is a copy of the counters (Table 7-6).
func (*OutstationAuth) Summary ¶
func (a *OutstationAuth) Summary() map[string]any
Summary describes the association's Secure Authentication for the status: the MAC algorithm, aggressive mode and each user's number, name, role and session key status (never a key).
func (*OutstationAuth) Users ¶
func (a *OutstationAuth) Users() []OutstationUser
Users lists the outstation's users (update keys included; never log them).
type OutstationAuthConfig ¶
type OutstationAuthConfig struct {
Users []OutstationUser // user 1 (default) is required
// MAL is the MAC algorithm of our challenges (default 4).
MAL uint8
// Critical is the request function codes challenged (default: the
// mandatory ones of Table 7-7).
Critical map[byte]bool
// Aggressive accepts aggressive-mode requests (7.6.1.4.7; default on).
Aggressive *bool
// ChallengeConfirms asks for aggressive-mode confirmations of
// responses with events (7.5.2.3.2 d).
ChallengeConfirms bool
// Expected session key change interval and count (7.6.1.4.5); the
// keys become invalid after either (defaults 30 min and 2000).
KeyInterval time.Duration
KeyCount int
// MaxKeyStatus is the key status requests allowed per user within the
// key interval before the operator is alerted (7.6.1.4.6; default 5).
MaxKeyStatus int
// MaxErrors is how many error messages are sent before they stop
// until the next key change (Table 7-6; default 2).
MaxErrors int
// MaxAuthFailures and MaxReplyTimeouts are the reporting thresholds
// of those statistics that act as moving limits (7.5.2.2, Table 7-15;
// defaults 5 and 3 as in Table 7-6). When authentication failures pass
// theirs the outstation drops a TCP connection (Table 7-8, 7.7.1);
// when reply timeouts pass theirs the key status of every user
// becomes COMM_FAIL (Table 7-8). ReplyTimeout is how long a challenge
// waits for its reply (1.12.3; default 5 s).
MaxAuthFailures int
MaxReplyTimeouts int
ReplyTimeout time.Duration
// Subject and Tenant name the association in security events.
Subject, Tenant string
// Update key change (7.5.5.5, 7.5.5.6): the outstation's name, the
// authority certification key (symmetric methods), the authority's
// certificate (asymmetric methods and g120v8), our RSA key (key
// transport), the areas of responsibility, the methods permitted.
Name string
AuthorityKey []byte
AuthorityCert *x509.Certificate
RSAKey *rsa.PrivateKey
AORs []string
Methods map[uint8]bool
// Roles reads and evaluates the IEC 62351-8 access token of g120v8
// user certificates (role definition, revision, role IDs, areas of
// responsibility, status change sequence number). When it is nil,
// NewRoles builds one for this outstation (its name, AORs and users'
// sequence numbers); when both are nil, user certificates are refused
// (ErrNoRoleAuthority).
Roles iotsec.RoleAuthority
NewRoles iotsec.NewRoleAuthority
// UserCertCheck, when set, checks a g120v8 ID certificate that
// verified against the authority (validity, revocation by CRL and
// OCSP through IEC 62351-9); an error refuses it.
UserCertCheck func(c *x509.Certificate) error
// UserChanged persists a user after an update key change or delete
// (Update nil: deleted).
UserChanged func(OutstationUser)
Log *slog.Logger
}
OutstationAuthConfig configures Secure Authentication as outstation.
type OutstationConfig ¶
type OutstationConfig struct {
Address uint16 // ours
Master uint16 // the master's
SelfAddress bool // accept frames to 0xFFFC (9.2.5.2.2)
Log *slog.Logger
DB *PointDB
Events *EventBuffer
Handler Handler
// MaxFragment is the largest response fragment (default 2048).
MaxFragment int
// ConfirmTimeout waits for an application confirmation (default 5 s).
ConfirmTimeout time.Duration
// SelectTimeout is how long a select stays valid (default 5 s).
SelectTimeout time.Duration
// MaxControls is the most control objects in one request (default 16).
MaxControls int
// Unsolicited: the unsolicited response mode (4.6.2.1 b). UnsolRetries
// is the retries per series (-1: indefinitely); UnsolHold delays a
// response after the first new event, UnsolCount sends at once when
// this many events are pending (4.6.2.2).
Unsolicited bool
UnsolRetries int
UnsolHold time.Duration
UnsolCount int
// UnsolOffline is the pause after a series that ended without a
// confirmation (its retries used up) before a new series carries the
// events still buffered (default: ConfirmTimeout).
UnsolOffline time.Duration
// NeedTime sets IIN1.4 at start and again this long after each
// synchronisation; 0 never asks for time.
NeedTime time.Duration
// Attributes are the device attributes of set 0 by variation, and
// Writable the variations the master may write.
Attributes map[uint8]any
Writable map[uint8]bool
// Auth enables Secure Authentication as outstation.
Auth *OutstationAuth
// Broadcast takes requests sent to the broadcast addresses (4.7;
// never answered). BroadcastFuncs, when set, are the request function
// codes carried out by broadcast (the device profile's 1.13 items);
// others are discarded. Under Secure Authentication a critical
// request by broadcast is carried out only in a verified Aggressive
// Mode (OutstationAuth.gateBroadcast).
Broadcast bool
BroadcastFuncs map[byte]bool
// Files enables sequential file transfer (outfile.go); FileStore, when
// set, is this association's store in place of Files.Store.
Files *OutstationFiles
FileStore FileStore
// Filter restricts the requests served to a declared device profile
// (a simulator preset): a non-zero IIN refuses the request with it.
Filter func(req Fragment) IIN
}
OutstationConfig configures one association.
type OutstationFiles ¶
type OutstationFiles struct {
Store FileStore
MaxBlock int // largest block (default 1024)
MaxOpen int // files open at once (default 4; rule 10)
MaxSize int // largest file written (default 16 MiB)
Idle time.Duration // inactivity before a handle closes (default 5 min, at most 1 h; rule 12)
Class int // class of spontaneous file events (default 3)
KeyLife time.Duration // an authentication key's life (default 1 min)
ReadOnly bool // refuse every write and delete
Users map[string]FileUser
// Guest are the rights with key 0 (5.3.1); nil: read and write when no
// users are configured, nothing otherwise.
Guest *FileRights
// Changed reports a file written ("written") or deleted ("deleted").
Changed func(ctx context.Context, path, op string, size int)
// contains filtered or unexported fields
}
OutstationFiles configures file transfer; one value may serve several associations (handles and locks are then shared: 5.3.8 rule 9).
type OutstationNet ¶
type OutstationNet struct {
Log *slog.Logger
KeepAlive time.Duration // default 30 s
Timeout time.Duration // link status answer; default 5 s
// contains filtered or unexported fields
}
OutstationNet routes frames to associations.
func (*OutstationNet) Add ¶
func (n *OutstationNet) Add(a *Association)
Add registers an association.
func (*OutstationNet) ServeStream ¶
func (n *OutstationNet) ServeStream(ctx context.Context, rw io.ReadWriteCloser)
ServeStream serves one connection until it ends or ctx is done.
type OutstationUser ¶
type OutstationUser struct {
Number uint16
Name string
UpdateKey []byte
Role uint16
Expires time.Time // zero: never
}
OutstationUser is one user of the outstation.
type Point ¶
type Point struct {
Group, Var uint8
Index uint32
// Value is a bool (binary, binary output, g80), a float64 (double-bit
// state 0–3, counters, analogs, delays) or a time.Time (g50, g51).
Value any
Flags uint8
HasFlags bool
Time time.Time // event time, when the object carries one
Status uint8 // command status (g12, g13, g41, g43)
CROB CROB // g12v1, g12v2
// Interval and Units are the interval of g50v2 (ms) and g50v4 (count
// and units code); Assoc is the association ID of g121 and g122; Ref
// is the group and variation a g81 fill status refers to.
Interval uint32
Units uint8
Assoc uint16
Ref [2]uint8
// Raw is the object data of variable-size objects: those with an
// object size prefix (g70, g91, g120, ...) and those whose variation
// is their length (g110 to g113).
Raw []byte
}
Point is one decoded object.
type PointDB ¶
type PointDB struct {
// contains filtered or unexported fields
}
PointDB is the outstation's database, shared by its associations.
func (*PointDB) AddEvent ¶
AddEvent buffers an event that is not a point change (a data set event, an authentication error) in every association.
func (*PointDB) Assign ¶
Assign changes the event class of the points of a type (all when indexes is nil); class 0 stops their events (4.4.14).
func (*PointDB) Attach ¶
func (db *PointDB) Attach(b *EventBuffer)
Attach registers an association's event buffer.
func (*PointDB) DataSet ¶
func (db *PointDB) DataSet(id uint32) (DataSetDef, bool)
DataSet returns a copy of a data set definition.
func (*PointDB) DataSetIDs ¶
DataSetIDs lists the data set identifiers in order.
func (*PointDB) DefineDataSet ¶
func (db *PointDB) DefineDataSet(d DataSetDef) error
DefineDataSet adds an outstation-defined data set (identifiers are contiguous from 0, 5.4.2.8.1).
func (*PointDB) DefinePrototype ¶
func (db *PointDB) DefinePrototype(p Descriptor) error
DefinePrototype adds a data set prototype.
func (*PointDB) Detach ¶
func (db *PointDB) Detach(b *EventBuffer)
Detach removes an association's event buffer.
func (*PointDB) Flat ¶
func (db *PointDB) Flat(id uint32) ([]DescElement, error)
Flat is a data set's data elements with prototypes resolved.
func (*PointDB) Freeze ¶
Freeze copies counters to frozen counters (clearing them with clear) and returns the frozen points changed.
func (*PointDB) Prototype ¶
func (db *PointDB) Prototype(id uint32) (Descriptor, bool)
Prototype returns a copy of a prototype.
func (*PointDB) PrototypeIDs ¶
PrototypeIDs lists the prototype identifiers in order.
func (*PointDB) SetDataSet ¶
func (db *PointDB) SetDataSet(ctx context.Context, id uint32, vals [][]byte, t time.Time, event bool) error
SetDataSet sets a data set's present value (and, with event, buffers a g88 event when the data set has an event class).
func (*PointDB) SetDeadband ¶
SetDeadband sets an analog point's deadband (g34 writes).
func (*PointDB) SetTimeAndInterval ¶ added in v0.2.0
func (db *PointDB) SetTimeAndInterval(index uint32, ti TimeAndInterval) error
SetTimeAndInterval sets a time-and-interval point (Index is ignored).
func (*PointDB) TimeAndInterval ¶ added in v0.2.0
func (db *PointDB) TimeAndInterval(index uint32) (TimeAndInterval, bool)
TimeAndInterval reads a time-and-interval point.
func (*PointDB) Update ¶
func (db *PointDB) Update(ctx context.Context, typ string, index uint32, v float64, raw []byte, flags uint8, t time.Time) (bool, error)
Update sets a point's value, flags and time and creates an event when the point has an event class and the value (or flags) changed beyond its deadband. It reports whether an event was created.
func (*PointDB) VirtualTerminalOutput ¶ added in v0.2.0
VirtualTerminalOutput queues data from a port as a virtual terminal event (1 to 255 octets).
func (*PointDB) WriteDataSet ¶
WriteDataSet stores a data set written by the master: it must be writable and match its complete structure (5.4.2.7).
func (*PointDB) WriteDescriptor ¶
func (db *PointDB) WriteDescriptor(d Descriptor) error
WriteDescriptor stores a master-defined data set descriptor (5.4.2.6.2); an outstation-defined one cannot be replaced.
func (*PointDB) WritePrototype ¶
func (db *PointDB) WritePrototype(p Descriptor) error
WritePrototype stores a master-defined prototype.
type Primary ¶
Primary is the primary-station state for confirmed user data towards one secondary peer (9.2.6.1, Table 9-4): whether its link states were reset and the next frame count bit.
func (*Primary) Acked ¶
func (p *Primary) Acked()
Acked records an ACK of the last confirmed frame: the next one toggles the frame count bit.
type Reassembler ¶
type Reassembler struct {
// contains filtered or unexported fields
}
Reassembler rebuilds application fragments from transport segments.
type RejectedError ¶
RejectedError is a request the outstation answered with IIN2 no-func-code-support, object-unknown or parameter-error.
func (*RejectedError) Error ¶
func (e *RejectedError) Error() string
Error names the internal indications of the rejection.
type Secondary ¶
type Secondary struct {
// contains filtered or unexported fields
}
Secondary is the secondary-station half of the data link layer for one primary peer (9.2.6, 9.2.8 Table 9-5): link reset state, the expected frame count bit and the last ACK or NACK sent, so a repeated TEST_LINK_STATES gets the same answer.
func (*Secondary) Handle ¶
func (s *Secondary) Handle(f Frame) LinkAction
Handle applies the secondary station rules to a primary frame addressed to this station (individually or by broadcast). Frames whose FCV does not match their function code are discarded (9.2.9). Nothing is ever answered to a broadcast destination, and confirmed user data sent to a broadcast address is discarded (9.2.4.1.3.6, 9.2.5.2.1).
type Secret ¶
type Secret string
Secret is a configuration value that never appears in logs or formatted output.
type SecurityEventEntry ¶
SecurityEventEntry is one recent Secure Authentication security event of an association: its time, name and the detail written to the security log (never key material).
type SessionConfig ¶ added in v0.2.0
type SessionConfig struct {
// Unsolicited lists the event classes to enable for unsolicited
// reporting at the end of the start-up; reporting is first disabled
// for every class. Empty: unsolicited reporting is disabled and stays
// so.
Unsolicited []int
// Integrity repeats the integrity poll (classes 1, 2, 3, 0); it also
// runs at start-up and after an event buffer overflow (IIN2.3).
// 0: no periodic integrity poll.
Integrity time.Duration
// Scans are periodic class scans.
Scans []ClassScan
// EventPoll polls the classes the outstation reports events for
// (IIN1.1 to 1.3).
EventPoll bool
// TimeSync sets the outstation's clock when it asks.
TimeSync TimeSyncMode
// AssignClass, when set, are the objects of an ASSIGN_CLASS request
// sent at start-up before the integrity poll.
AssignClass []byte
// RetryDelay is the pause after a failed task (default 5 s).
RetryDelay time.Duration
// OnData receives the response fragments of the session's polls
// (unsolicited responses go to MasterConfig.OnUnsolicited).
OnData func(Fragment)
// OnTask reports each task run ("disable unsolicited", "clear
// restart", "assign class", "integrity", "time sync", "enable
// unsolicited", "class N scan", "event poll") and its error.
OnTask func(name string, err error)
}
SessionConfig configures RunSession.
type StatusElement ¶
StatusElement is one status element of a g91v1.
type SymmetricAuthority ¶
type SymmetricAuthority struct {
KeyChangeMethod uint8
Key []byte // AES-128 for method 3, AES-256 for methods 4 and 5
MasterAddress uint16
}
SymmetricAuthority is an authority sharing the authority certification key with the outstation (methods 3, 4 and 5). MasterAddress is the sender address of the AES-GMAC IV (method 5).
func (SymmetricAuthority) Certify ¶
func (s SymmetricAuthority) Certify(u UserStatus) ([]byte, error)
Certify is the HMAC of the status information with the authority key.
func (SymmetricAuthority) EncryptUpdateKey ¶
func (s SymmetricAuthority) EncryptUpdateKey(name string, key, ostnChallenge []byte) ([]byte, error)
EncryptUpdateKey wraps the update key data with the authority key.
func (SymmetricAuthority) Method ¶
func (s SymmetricAuthority) Method() uint8
Method is the key change method.
type TimeAndInterval ¶ added in v0.2.0
TimeAndInterval is the value of a time-and-interval point.
type TimeAndIntervalHandler ¶ added in v0.2.0
type TimeAndIntervalHandler interface {
TimeAndIntervalWritten(ctx context.Context, ti TimeAndInterval)
}
TimeAndIntervalHandler is implemented by a Handler that wants to know when the master wrote a time-and-interval point (the database already holds the new value).
type TimeSyncMode ¶ added in v0.2.0
type TimeSyncMode int
TimeSyncMode selects how a session sets the outstation's clock when the outstation asks for it (IIN1.4).
const ( TimeSyncNone TimeSyncMode = iota TimeSyncNonLAN // DELAY_MEASURE, then WRITE g50v1 TimeSyncLAN // RECORD_CURRENT_TIME, then WRITE g50v3 )
type UpdateKeyChange ¶
type UpdateKeyChange struct {
Authority Authority
Operation uint8 // UserAdd (default), UserChange or UserDelete
SCS uint32
UserName string
Role uint16
Expiry uint16 // days
Outstation string // the outstation's name, as configured at the authority
NewKey []byte // generated when empty
// Asymmetric methods: the user's key pair (the public key goes to the
// outstation in the status change) and the outstation's RSA key.
UserKey *dsa.PrivateKey
UserPublicKey []byte // SubjectPublicKeyInfo octets
OutstationKey *rsa.PublicKey
// Certificate, for the asymmetric methods, is an IEC/TS 62351-8
// certificate from the authority sent as a g120v8 instead of the
// g120v10 (CertificateType 1 ID or 2 attribute; default 1).
Certificate []byte
CertificateType uint8
}
UpdateKeyChange describes one user status and update key change.
type UpdateKeyReply ¶
type UpdateKeyReply struct {
KSQ uint32
User uint16
Data []byte // outstation challenge data (v12) or encrypted update key data (v13)
}
UpdateKeyReply is g120v12 (and, with Data the encrypted key, the head of g120v13).
func ParseUpdateKeyReply ¶
func ParseUpdateKeyReply(d []byte) (UpdateKeyReply, error)
ParseUpdateKeyReply decodes g120v12 or g120v13 object data.
func (UpdateKeyReply) Encode ¶
func (r UpdateKeyReply) Encode() []byte
Encode is the g120v12 or g120v13 object data.
type UpdateKeyRequest ¶
UpdateKeyRequest is g120v11.
func ParseUpdateKeyRequest ¶
func ParseUpdateKeyRequest(d []byte) (UpdateKeyRequest, error)
ParseUpdateKeyRequest decodes g120v11 object data.
func (UpdateKeyRequest) Encode ¶
func (r UpdateKeyRequest) Encode() []byte
Encode is the g120v11 object data.
type UserCertificate ¶
UserCertificate is a g120v8.
func ParseUserCertificate ¶
func ParseUserCertificate(b []byte) (UserCertificate, error)
ParseUserCertificate decodes a g120v8.
type UserRoleInfo ¶
type UserRoleInfo struct {
Roles []int
AOR string `asn1:"utf8"`
Revision int
RoleDefinition string `asn1:"optional,utf8"`
Operation asn1.Enumerated `asn1:"optional"`
SCS int64 `asn1:"optional"`
}
UserRoleInfo is one IECUserRoles entry.
type UserStatus ¶
type UserStatus struct {
Method uint8
Operation uint8
SCS uint32 // status change sequence number
Role uint16
Expiry uint16 // days after reception
Name string
PublicKey []byte // asymmetric methods: the user's SubjectPublicKeyInfo
CertData []byte
}
UserStatus is the user status information of a g120v10.
func ParseUserStatus ¶
func ParseUserStatus(d []byte) (UserStatus, error)
ParseUserStatus decodes g120v10 object data.
func (UserStatus) StatusInfo ¶
func (u UserStatus) StatusInfo() []byte
StatusInfo is the data the authority certifies (Table A-10, in order).