Netpulse_SasS/gen/go/netpulse/v1/logs.pb.go
byrsapty ddaae60fa0 Етап 8: реєстрація зонда одноразовим запрошенням
Найбільше вузьке місце до запуску: агент заводився INSERT-ом у базу, а
токен вписувався в командний рядок руками. Поставити зонд у клієнта було
неможливо.

core.agent_enrollments тримає sha256 одноразового токена; сам токен
повертається рівно один раз. Видача під FOR UPDATE в одній транзакції:
два агенти з однієї скопійованої команди інакше створили б два зонди з
одного запрошення. Відповідь на «немає», «згоріло» і «використано»
однакова — розрізняти їх означає підказувати тому, хто підбирає токени.

Токен зонда їде окремим полем agent_token, а не в certificate:
сертифікат відповідає на інше питання й живе за іншим циклом.

Агент зберігає посвідчення в /etc/netpulse/agent.json з правами 0600,
через тимчасовий файл і перейменування — обрив живлення посеред запису
інакше лишив би половину токена.

Знайдено живим прогоном: реєстрація не проходила автентифікацію, бо
інтерсептор стоїть на всьому сервері, а не на окремому сервісі — мій же
коментар стверджував протилежне. І запуск із самим посвідченням падав:
validate() вимагав -agent-id, не знаючи про файл.

Сторінка зондів: команда встановлення з токеном, відкликання
запрошень, керування модулями й лімітами, видалення.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 00:50:57 +03:00

540 lines
17 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// =====================================================================
// NetPulse :: logs.proto
// Syslog та SNMP-трапи, зібрані агентом. → ts.syslog / ts.snmp_traps
//
// Агент слухає 514/udp і 162/udp у мережі клієнта й тунелює події
// назовні. Це важливо не лише для журналу: подія "%SYS-5-CONFIG_I"
// тригерить позачерговий бекап конфігу (ncm.device_policies.on_syslog).
// =====================================================================
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.12
// protoc (unknown)
// source: netpulse/v1/logs.proto
package netpulsev1
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type SyslogEntry struct {
state protoimpl.MessageState `protogen:"open.v1"`
Ts *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=ts,proto3" json:"ts,omitempty"`
// Резолвиться агентом за source_ip; порожній, якщо пристрій невідомий.
DeviceId string `protobuf:"bytes,2,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
SourceIp string `protobuf:"bytes,3,opt,name=source_ip,json=sourceIp,proto3" json:"source_ip,omitempty"`
Facility uint32 `protobuf:"varint,4,opt,name=facility,proto3" json:"facility,omitempty"`
Severity uint32 `protobuf:"varint,5,opt,name=severity,proto3" json:"severity,omitempty"` // 0 emerg .. 7 debug
Hostname string `protobuf:"bytes,6,opt,name=hostname,proto3" json:"hostname,omitempty"`
Tag string `protobuf:"bytes,7,opt,name=tag,proto3" json:"tag,omitempty"`
Message string `protobuf:"bytes,8,opt,name=message,proto3" json:"message,omitempty"`
// Розібрані поля, якщо агент упізнав формат (RFC5424 structured data).
Parsed map[string]string `protobuf:"bytes,9,rep,name=parsed,proto3" json:"parsed,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SyslogEntry) Reset() {
*x = SyslogEntry{}
mi := &file_netpulse_v1_logs_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SyslogEntry) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SyslogEntry) ProtoMessage() {}
func (x *SyslogEntry) ProtoReflect() protoreflect.Message {
mi := &file_netpulse_v1_logs_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SyslogEntry.ProtoReflect.Descriptor instead.
func (*SyslogEntry) Descriptor() ([]byte, []int) {
return file_netpulse_v1_logs_proto_rawDescGZIP(), []int{0}
}
func (x *SyslogEntry) GetTs() *timestamppb.Timestamp {
if x != nil {
return x.Ts
}
return nil
}
func (x *SyslogEntry) GetDeviceId() string {
if x != nil {
return x.DeviceId
}
return ""
}
func (x *SyslogEntry) GetSourceIp() string {
if x != nil {
return x.SourceIp
}
return ""
}
func (x *SyslogEntry) GetFacility() uint32 {
if x != nil {
return x.Facility
}
return 0
}
func (x *SyslogEntry) GetSeverity() uint32 {
if x != nil {
return x.Severity
}
return 0
}
func (x *SyslogEntry) GetHostname() string {
if x != nil {
return x.Hostname
}
return ""
}
func (x *SyslogEntry) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
func (x *SyslogEntry) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *SyslogEntry) GetParsed() map[string]string {
if x != nil {
return x.Parsed
}
return nil
}
type SnmpTrap struct {
state protoimpl.MessageState `protogen:"open.v1"`
Ts *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=ts,proto3" json:"ts,omitempty"`
DeviceId string `protobuf:"bytes,2,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
SourceIp string `protobuf:"bytes,3,opt,name=source_ip,json=sourceIp,proto3" json:"source_ip,omitempty"`
TrapOid string `protobuf:"bytes,4,opt,name=trap_oid,json=trapOid,proto3" json:"trap_oid,omitempty"`
Varbinds []*VarBind `protobuf:"bytes,5,rep,name=varbinds,proto3" json:"varbinds,omitempty"`
// v2c community або v3 security name — сервер перевіряє довіру джерела.
AuthContext string `protobuf:"bytes,6,opt,name=auth_context,json=authContext,proto3" json:"auth_context,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SnmpTrap) Reset() {
*x = SnmpTrap{}
mi := &file_netpulse_v1_logs_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SnmpTrap) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SnmpTrap) ProtoMessage() {}
func (x *SnmpTrap) ProtoReflect() protoreflect.Message {
mi := &file_netpulse_v1_logs_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SnmpTrap.ProtoReflect.Descriptor instead.
func (*SnmpTrap) Descriptor() ([]byte, []int) {
return file_netpulse_v1_logs_proto_rawDescGZIP(), []int{1}
}
func (x *SnmpTrap) GetTs() *timestamppb.Timestamp {
if x != nil {
return x.Ts
}
return nil
}
func (x *SnmpTrap) GetDeviceId() string {
if x != nil {
return x.DeviceId
}
return ""
}
func (x *SnmpTrap) GetSourceIp() string {
if x != nil {
return x.SourceIp
}
return ""
}
func (x *SnmpTrap) GetTrapOid() string {
if x != nil {
return x.TrapOid
}
return ""
}
func (x *SnmpTrap) GetVarbinds() []*VarBind {
if x != nil {
return x.Varbinds
}
return nil
}
func (x *SnmpTrap) GetAuthContext() string {
if x != nil {
return x.AuthContext
}
return ""
}
type VarBind struct {
state protoimpl.MessageState `protogen:"open.v1"`
Oid string `protobuf:"bytes,1,opt,name=oid,proto3" json:"oid,omitempty"`
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` // INTEGER, OCTET STRING, Counter64, ...
Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *VarBind) Reset() {
*x = VarBind{}
mi := &file_netpulse_v1_logs_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *VarBind) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VarBind) ProtoMessage() {}
func (x *VarBind) ProtoReflect() protoreflect.Message {
mi := &file_netpulse_v1_logs_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use VarBind.ProtoReflect.Descriptor instead.
func (*VarBind) Descriptor() ([]byte, []int) {
return file_netpulse_v1_logs_proto_rawDescGZIP(), []int{2}
}
func (x *VarBind) GetOid() string {
if x != nil {
return x.Oid
}
return ""
}
func (x *VarBind) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *VarBind) GetValue() string {
if x != nil {
return x.Value
}
return ""
}
type LogBatch struct {
state protoimpl.MessageState `protogen:"open.v1"`
BatchId uint64 `protobuf:"varint,1,opt,name=batch_id,json=batchId,proto3" json:"batch_id,omitempty"`
AgentId string `protobuf:"bytes,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
Syslog []*SyslogEntry `protobuf:"bytes,3,rep,name=syslog,proto3" json:"syslog,omitempty"`
Traps []*SnmpTrap `protobuf:"bytes,4,rep,name=traps,proto3" json:"traps,omitempty"`
// Скільки подій агент відкинув через переповнення (rate limit).
// Ненульове — сигнал, що клієнт шумить або ліміт замалий.
Dropped uint64 `protobuf:"varint,5,opt,name=dropped,proto3" json:"dropped,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *LogBatch) Reset() {
*x = LogBatch{}
mi := &file_netpulse_v1_logs_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *LogBatch) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LogBatch) ProtoMessage() {}
func (x *LogBatch) ProtoReflect() protoreflect.Message {
mi := &file_netpulse_v1_logs_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LogBatch.ProtoReflect.Descriptor instead.
func (*LogBatch) Descriptor() ([]byte, []int) {
return file_netpulse_v1_logs_proto_rawDescGZIP(), []int{3}
}
func (x *LogBatch) GetBatchId() uint64 {
if x != nil {
return x.BatchId
}
return 0
}
func (x *LogBatch) GetAgentId() string {
if x != nil {
return x.AgentId
}
return ""
}
func (x *LogBatch) GetSyslog() []*SyslogEntry {
if x != nil {
return x.Syslog
}
return nil
}
func (x *LogBatch) GetTraps() []*SnmpTrap {
if x != nil {
return x.Traps
}
return nil
}
func (x *LogBatch) GetDropped() uint64 {
if x != nil {
return x.Dropped
}
return 0
}
type LogAck struct {
state protoimpl.MessageState `protogen:"open.v1"`
AckedThroughBatchId uint64 `protobuf:"varint,1,opt,name=acked_through_batch_id,json=ackedThroughBatchId,proto3" json:"acked_through_batch_id,omitempty"`
// Сервер просить фільтрувати шум на агенті: не слати нижче цієї severity.
MinSeverity uint32 `protobuf:"varint,2,opt,name=min_severity,json=minSeverity,proto3" json:"min_severity,omitempty"`
// Ліміт подій за секунду з одного джерела.
RateLimitPerSource uint32 `protobuf:"varint,3,opt,name=rate_limit_per_source,json=rateLimitPerSource,proto3" json:"rate_limit_per_source,omitempty"`
Error *Error `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *LogAck) Reset() {
*x = LogAck{}
mi := &file_netpulse_v1_logs_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *LogAck) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LogAck) ProtoMessage() {}
func (x *LogAck) ProtoReflect() protoreflect.Message {
mi := &file_netpulse_v1_logs_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use LogAck.ProtoReflect.Descriptor instead.
func (*LogAck) Descriptor() ([]byte, []int) {
return file_netpulse_v1_logs_proto_rawDescGZIP(), []int{4}
}
func (x *LogAck) GetAckedThroughBatchId() uint64 {
if x != nil {
return x.AckedThroughBatchId
}
return 0
}
func (x *LogAck) GetMinSeverity() uint32 {
if x != nil {
return x.MinSeverity
}
return 0
}
func (x *LogAck) GetRateLimitPerSource() uint32 {
if x != nil {
return x.RateLimitPerSource
}
return 0
}
func (x *LogAck) GetError() *Error {
if x != nil {
return x.Error
}
return nil
}
var File_netpulse_v1_logs_proto protoreflect.FileDescriptor
const file_netpulse_v1_logs_proto_rawDesc = "" +
"\n" +
"\x16netpulse/v1/logs.proto\x12\vnetpulse.v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x18netpulse/v1/common.proto\"\xec\x02\n" +
"\vSyslogEntry\x12*\n" +
"\x02ts\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\x02ts\x12\x1b\n" +
"\tdevice_id\x18\x02 \x01(\tR\bdeviceId\x12\x1b\n" +
"\tsource_ip\x18\x03 \x01(\tR\bsourceIp\x12\x1a\n" +
"\bfacility\x18\x04 \x01(\rR\bfacility\x12\x1a\n" +
"\bseverity\x18\x05 \x01(\rR\bseverity\x12\x1a\n" +
"\bhostname\x18\x06 \x01(\tR\bhostname\x12\x10\n" +
"\x03tag\x18\a \x01(\tR\x03tag\x12\x18\n" +
"\amessage\x18\b \x01(\tR\amessage\x12<\n" +
"\x06parsed\x18\t \x03(\v2$.netpulse.v1.SyslogEntry.ParsedEntryR\x06parsed\x1a9\n" +
"\vParsedEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xe0\x01\n" +
"\bSnmpTrap\x12*\n" +
"\x02ts\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\x02ts\x12\x1b\n" +
"\tdevice_id\x18\x02 \x01(\tR\bdeviceId\x12\x1b\n" +
"\tsource_ip\x18\x03 \x01(\tR\bsourceIp\x12\x19\n" +
"\btrap_oid\x18\x04 \x01(\tR\atrapOid\x120\n" +
"\bvarbinds\x18\x05 \x03(\v2\x14.netpulse.v1.VarBindR\bvarbinds\x12!\n" +
"\fauth_context\x18\x06 \x01(\tR\vauthContext\"E\n" +
"\aVarBind\x12\x10\n" +
"\x03oid\x18\x01 \x01(\tR\x03oid\x12\x12\n" +
"\x04type\x18\x02 \x01(\tR\x04type\x12\x14\n" +
"\x05value\x18\x03 \x01(\tR\x05value\"\xb9\x01\n" +
"\bLogBatch\x12\x19\n" +
"\bbatch_id\x18\x01 \x01(\x04R\abatchId\x12\x19\n" +
"\bagent_id\x18\x02 \x01(\tR\aagentId\x120\n" +
"\x06syslog\x18\x03 \x03(\v2\x18.netpulse.v1.SyslogEntryR\x06syslog\x12+\n" +
"\x05traps\x18\x04 \x03(\v2\x15.netpulse.v1.SnmpTrapR\x05traps\x12\x18\n" +
"\adropped\x18\x05 \x01(\x04R\adropped\"\xbd\x01\n" +
"\x06LogAck\x123\n" +
"\x16acked_through_batch_id\x18\x01 \x01(\x04R\x13ackedThroughBatchId\x12!\n" +
"\fmin_severity\x18\x02 \x01(\rR\vminSeverity\x121\n" +
"\x15rate_limit_per_source\x18\x03 \x01(\rR\x12rateLimitPerSource\x12(\n" +
"\x05error\x18\x04 \x01(\v2\x12.netpulse.v1.ErrorR\x05errorB\xa5\x01\n" +
"\x0fcom.netpulse.v1B\tLogsProtoP\x01Z:github.com/netpulse/netpulse/gen/go/netpulse/v1;netpulsev1\xa2\x02\x03NXX\xaa\x02\vNetpulse.V1\xca\x02\vNetpulse\\V1\xe2\x02\x17Netpulse\\V1\\GPBMetadata\xea\x02\fNetpulse::V1b\x06proto3"
var (
file_netpulse_v1_logs_proto_rawDescOnce sync.Once
file_netpulse_v1_logs_proto_rawDescData []byte
)
func file_netpulse_v1_logs_proto_rawDescGZIP() []byte {
file_netpulse_v1_logs_proto_rawDescOnce.Do(func() {
file_netpulse_v1_logs_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_netpulse_v1_logs_proto_rawDesc), len(file_netpulse_v1_logs_proto_rawDesc)))
})
return file_netpulse_v1_logs_proto_rawDescData
}
var file_netpulse_v1_logs_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_netpulse_v1_logs_proto_goTypes = []any{
(*SyslogEntry)(nil), // 0: netpulse.v1.SyslogEntry
(*SnmpTrap)(nil), // 1: netpulse.v1.SnmpTrap
(*VarBind)(nil), // 2: netpulse.v1.VarBind
(*LogBatch)(nil), // 3: netpulse.v1.LogBatch
(*LogAck)(nil), // 4: netpulse.v1.LogAck
nil, // 5: netpulse.v1.SyslogEntry.ParsedEntry
(*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp
(*Error)(nil), // 7: netpulse.v1.Error
}
var file_netpulse_v1_logs_proto_depIdxs = []int32{
6, // 0: netpulse.v1.SyslogEntry.ts:type_name -> google.protobuf.Timestamp
5, // 1: netpulse.v1.SyslogEntry.parsed:type_name -> netpulse.v1.SyslogEntry.ParsedEntry
6, // 2: netpulse.v1.SnmpTrap.ts:type_name -> google.protobuf.Timestamp
2, // 3: netpulse.v1.SnmpTrap.varbinds:type_name -> netpulse.v1.VarBind
0, // 4: netpulse.v1.LogBatch.syslog:type_name -> netpulse.v1.SyslogEntry
1, // 5: netpulse.v1.LogBatch.traps:type_name -> netpulse.v1.SnmpTrap
7, // 6: netpulse.v1.LogAck.error:type_name -> netpulse.v1.Error
7, // [7:7] is the sub-list for method output_type
7, // [7:7] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
}
func init() { file_netpulse_v1_logs_proto_init() }
func file_netpulse_v1_logs_proto_init() {
if File_netpulse_v1_logs_proto != nil {
return
}
file_netpulse_v1_common_proto_init()
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_netpulse_v1_logs_proto_rawDesc), len(file_netpulse_v1_logs_proto_rawDesc)),
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_netpulse_v1_logs_proto_goTypes,
DependencyIndexes: file_netpulse_v1_logs_proto_depIdxs,
MessageInfos: file_netpulse_v1_logs_proto_msgTypes,
}.Build()
File_netpulse_v1_logs_proto = out.File
file_netpulse_v1_logs_proto_goTypes = nil
file_netpulse_v1_logs_proto_depIdxs = nil
}