Diameter stack and Base Protocol (RFC 6733) for the Go programming language

Related tags

Network go-diameter
Overview

Diameter Base Protocol

Package go-diameter is an implementation of the Diameter Base Protocol RFC 6733 and a stack for the Go programming language.

GoDoc

Status

The current implementation is solid and works fine for general purpose clients and servers. It can send and receive messages efficiently as well as build and parse AVPs based on dictionaries.

See the API documentation at http://godoc.org/github.com/fiorix/go-diameter

Build Status

Features

  • Comprehensive XML dictionary format
  • Embedded dictionaries:
  • Human readable AVP representation (for debugging)
  • TLS, IPv4 and IPv6 support for both clients and servers
  • Stack based on net/http for simplicity
  • Ships with sample client, server, snoop agent and benchmark tool
  • State machines for CER/CEA and DWR/DWA for clients and servers
  • TCP and SCTP support. SCTP support relies on kernel SCTP implementation and external github.com/ishidawataru/sctp package and is currently tested and enabled for Go 1.8+ and x86 Linux

Getting started

The easiest way to get started is by trying out the client and server example programs.

With Go 1.11 and newer (preferred), you can start the client and server already:

export GO111MODULE=on
go run github.com/fiorix/go-diameter/v4/examples/server
go run github.com/fiorix/go-diameter/v4/examples/client -hello

Without modules, use standard procedure:

go get github.com/fiorix/go-diameter/examples/...
go run github.com/fiorix/go-diameter/examples/server
go run github.com/fiorix/go-diameter/examples/client -hello

Source code is your best friend. Check out other examples and test cases.

Performance

Clients and servers written with the go-diameter package can be quite performant if done well. Besides Go benchmarks, the package ships with a simple benchmark tool to help testing servers and identifying bottlenecks.

In the examples directory, the server has a pprof (http server) that allows the go pprof tool to profile the server in real time. The client can perform benchmarks using the -bench command line flag.

For better performance, avoid logging diameter messages. Although logging is very useful for debugging purposes, it kills performance due to a number of conversions to make messages look pretty. If you run benchmarks on the example server, make sure to use the -s (silent) command line switch.

TLS degrades performance a bit, as well as reflection (Unmarshal). Those are important trade offs you might have to consider.

Besides this, the source code (and sub-packages) have function benchmarks that can help you understand what's fast and isn't. You will see that parsing messages is much slower than writing them, for example. This is because in order to parse messages it makes numerous dictionary lookups for AVP types, to be able to decode them. Encoding messages require less lookups and is generally simpler, thus faster.

Comments
  • Updating AVP values

    Updating AVP values

    It would be useful to add a method for updating AVP values. Currently I have been using this helper function:

    func ReplaceAVPValue(m *diam.Message, avpName string, avpValue datatype.Type) error {

    avp, err := m.FindAVP(avpName)
    
    if err != nil {
        return err
    }
    
    oldLength := avp.Len()
    avp.Data = avpValue
    newLength := avp.Len()
    m.Header.MessageLength += uint32(newLength) - uint32(oldLength)
    
    return nil
    

    }

    But I'm not sure if it works for AVPs that are inside grouped AVP.

    opened by taseppa 26
  • fix for common apps handling

    fix for common apps handling

    Not supported apps are logged to console without specifying whether id is local or remote, however local can still be recognized by 'missing application' error. Connection is established when remote peer returns ids unknown locally, but common applications exist.

    opened by jaroszan 19
  • Unsupported address family: 0x0008

    Unsupported address family: 0x0008

    When I receive a message I get an error as in subj.

    Ethernet layer in wireshark says:

    Type: IPv4 (0x0800)
    

    IP layer is decoded as:

    Internet Protocol Version 4, Src: 172.20.21.7, Dst: 172.20.17.37
    0100 .... = Version: 4
    .... 0101 = Header Length: 20 bytes
    Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
    Total Length: 580
    Identification: 0xa4a1 (42145)
    Flags: 0x02 (Don't Fragment)
    Fragment offset: 0
    Time to live: 62
    Protocol: TCP (6)
    Header checksum: 0x5a51 [validation disabled]
    Source: 172.20.21.7
    Destination: 172.20.17.37
    [Source GeoIP: Unknown]
    [Destination GeoIP: Unknown]
    
    opened by jaroszan 19
  • Problem having vendor specific AVP with an existing AVP code

    Problem having vendor specific AVP with an existing AVP code

    According to RFC: "The AVP Code, combined with the Vendor-Id field, identifies the attribute uniquely."

    But currently I seem to have some parsing problems if you use a vendor specific AVP with a code that already exists. At least in avp/codes.go this looks a bit odd:

    dictAVP, err := dictionary.FindAVP(application, a.Code)

    Because the FindAVP doesn't take vendorId as parameter.

    opened by taseppa 17
  • Unsupported mandatory AVP found in Base package

    Unsupported mandatory AVP found in Base package

    Hello Fiorix!

    I am trying to make GoDiameter to communicate with freeDiameter respectively. However, received CEA includes three application Ids and one unknown AVP. Despite DIAMETER_SUCCESS (2001) , freeDiameter fails to parse the response correctly.

    freeDiameter Log:

    18:02:54  NOTI   SND to 'cgrates-poc.opencloud.com':
    18:02:54  NOTI        'Capabilities-Exchange-Request'
    18:02:54  NOTI          Version: 0x01
    18:02:54  NOTI          Length: 212
    18:02:54  NOTI          Flags: 0x80 (R---)
    18:02:54  NOTI          Command Code: 257
    18:02:54  NOTI          ApplicationId: 0
    18:02:54  NOTI          Hop-by-Hop Identifier: 0x1BFA6EE1
    18:02:54  NOTI          End-to-End Identifier: 0x8E10F059
    18:02:54  NOTI           {internal data}: src:(nil)(0) rwb:(nil) rt:0 cb:(nil),(nil)((nil)) qry:(nil) asso:0 sess:(nil)
    18:02:54  NOTI           AVP: 'Origin-Host'(264) l=34 f=-M val="freediameter.opencloud.com"
    18:02:54  NOTI           AVP: 'Origin-Realm'(296) l=21 f=-M val="opencloud.com"
    18:02:54  NOTI           AVP: 'Origin-State-Id'(278) l=12 f=-M val=1492441313 (0x58f4d8e1)
    18:02:54  NOTI           AVP: 'Host-IP-Address'(257) l=14 f=-M val=10.224.228.36
    18:02:54  NOTI           AVP: 'Vendor-Id'(266) l=12 f=-M val=0 (0x0)
    18:02:54  NOTI           AVP: 'Product-Name'(269) l=20 f=-- val="freeDiameter"
    18:02:54  NOTI           AVP: 'Firmware-Revision'(267) l=12 f=-- val=10201 (0x27d9)
    18:02:54  NOTI           AVP: 'Inband-Security-Id'(299) l=12 f=-M val='NO_INBAND_SECURITY' (0 (0x0))
    18:02:54  NOTI           AVP: 'Acct-Application-Id'(259) l=12 f=-M val=3 (0x3)
    18:02:54  NOTI           AVP: 'Auth-Application-Id'(258) l=12 f=-M val=4294967295 (0xffffffff)
    18:02:54  NOTI           AVP: 'Supported-Vendor-Id'(265) l=12 f=-M val=5535 (0x159f)
    18:02:54  NOTI           AVP: 'Supported-Vendor-Id'(265) l=12 f=-M val=10415 (0x28af)
    18:02:54   DBG   'STATE_WAITCNXACK'     -> 'STATE_WAITCEA'      'cgrates-poc.opencloud.com'
    18:02:54  NOTI   Unsupported mandatory AVP found
    18:02:54  ERROR  Unsupported AVP: 0(not searched in dictionary) l=12 f=-M val=(not set)
    18:02:54  ERROR  ERROR: in '((parsedict_do_avp(dict, ((struct avp *)(avpch->o)), mandatory, error_info)))' :    Operation not supported
    18:02:54  ERROR  ERROR: in '((parsedict_do_avp(dict, ((struct avp *)(avpch->o)), mandatory, error_info)))' :    Operation not supported
    18:02:54  NOTI   RCV from 'cgrates-poc.opencloud.com':
    18:02:54  NOTI        'Capabilities-Exchange-Answer'
    18:02:54  NOTI          Version: 0x01
    18:02:54  NOTI          Length: 228
    18:02:54  NOTI          Flags: 0x00 (----)
    18:02:54  NOTI          Command Code: 257
    18:02:54  NOTI          ApplicationId: 0
    18:02:54  NOTI          Hop-by-Hop Identifier: 0x1BFA6EE1
    18:02:54  NOTI          End-to-End Identifier: 0x8E10F059
    18:02:54  NOTI           {internal data}: src:cgrates-poc.opencloud.com(25) rwb:0x7f8ffc0019f0 rt:0 cb:(nil),(nil)((nil)) qry:0x7f90040012f0 asso:0 sess:(nil)
    18:02:54  NOTI           AVP: 'Result-Code'(268) l=12 f=-M val='DIAMETER_SUCCESS' (2001 (0x7d1))
    18:02:54  NOTI           AVP: 'Origin-Host'(264) l=19 f=-M val="cgrates-poc"
    18:02:54  NOTI           AVP: 'Origin-Realm'(296) l=21 f=-M val="opencloud.com"
    18:02:54  NOTI           AVP: 'Host-IP-Address'(257) l=14 f=-M val=10.224.228.186
    18:02:54  NOTI           AVP: 'Vendor-Id'(266) l=12 f=-M val=0 (0x0)
    18:02:54  NOTI           AVP: 'Product-Name'(269) l=19 f=-- val="Golant-data"
    18:02:54  NOTI           AVP: 'Origin-State-Id'(278) l=12 f=-M val=1492441313 (0x58f4d8e1)
    18:02:54  NOTI           AVP: 'Acct-Application-Id'(259) l=12 f=-M val=3 (0x3)
    18:02:54  NOTI           AVP: 'Auth-Application-Id'(258) l=12 f=-M val=4 (0x4)
    18:02:54  NOTI           AVP: 'Auth-Application-Id'(258) l=12 f=-M val=1 (0x1)
    18:02:54  NOTI           AVP: 'Supported-Vendor-Id'(265) l=12 f=-M val=10415 (0x28af)
    18:02:54  NOTI           AVP: 'Vendor-Specific-Application-Id'(260) l=32 f=-M val=(grouped)
    18:02:54  NOTI              AVP: 'Vendor-Id'(266) l=12 f=-M val=10415 (0x28af)
    18:02:54  NOTI              AVP: 0(not searched in dictionary) l=12 f=-M val=(not set)
    18:02:54  NOTI           AVP: 267(not searched in dictionary) l=12 f=-- val=(not set)
    18:02:54  NOTI   Unsupported mandatory AVP found
    

    Trace:

    Diameter Protocol
        Version: 0x01
        Length: 196
        Flags: 0x00
        Command Code: 257 Capabilities-Exchange
        ApplicationId: Diameter Common Messages (0)
        Hop-by-Hop Identifier: 0x5ff41e87
        End-to-End Identifier: 0xc68a0593
        [Request In: 124]
        [Response Time: 0.000189000 seconds]
        AVP: Result-Code(268) l=12 f=-M- val=DIAMETER_SUCCESS (2001)
        AVP: Origin-Host(264) l=19 f=-M- val=cgrates-poc
        AVP: Origin-Realm(296) l=21 f=-M- val=opencloud.com
        AVP: Host-IP-Address(257) l=14 f=-M- val=10.224.228.186
        AVP: Vendor-Id(266) l=12 f=-M- val=10415
        AVP: Product-Name(269) l=19 f=--- val=Golant-data
        AVP: Origin-State-Id(278) l=12 f=-M- val=1492106344
        AVP: Acct-Application-Id(259) l=12 f=-M- val=Diameter Base Accounting (3)
        AVP: Auth-Application-Id(258) l=12 f=-M- val=Diameter Credit Control Application (4)
        AVP: Auth-Application-Id(258) l=12 f=-M- val=NASREQ Application (1)
        **AVP: Unknown(0) l=12 f=-M- val=00000004**
        AVP: Firmware-Revision(267) l=12 f=--- val=918
    
    

    From the documentation, I understand that actually four dictionaries (applications) are pre-loaded in.

    Embedded dictionaries:
    
    - Base Protocol RFC 6733
    - Credit Control RFC 4006
    - Network Access Server RFC 7155
    - 3GPP specific AVPs from TS 32.299 version 12.7.0  <=== What is that exactly and what is used for ?
    

    I am a newbie in diameter world, but I feel, it could be related to to RFC3588 and "Vendor-Specific-Application-Id" grouped AVP. Could you kindly point me towards the reason why that particular unknown AVP appears in the answer and which dictionary could possibly make freeDiameter understand that?

    Is there a way to disable those specific AVPs from being added to CEA, since I only need DCCA?

    Just tried to comment out the following in the autogen.sh file, and running it, then building the project.

    
    // Default is a Parser object with pre-loaded
    // Base Protocol and Credit Control dictionaries.
    var Default *Parser
    
    func init() {
            Default, _ = NewParser()
    //      Default.Load(bytes.NewReader([]byte(baseXML)))
            Default.Load(bytes.NewReader([]byte(creditcontrolXML)))
    //      Default.Load(bytes.NewReader([]byte(networkaccessserverXML)))
    //      Default.Load(bytes.NewReader([]byte(tgpprorfXML)))
    }
    
    

    The AVP is removed, but freeDiameter rejects the session without base dictionary, so, I think it is mandatory. This is more like a question, still not sure where is the exact issue.

    Please assist, Thanks in advance,

    opened by muxalko 14
  • OctetString should be initialized from string of octets, not as text.

    OctetString should be initialized from string of octets, not as text.

    It seems that there is an issue with OctetString datatype, according to ASN.1 OCTET STRING is a string of octets and should be initialized as a string of octets, not from quoted text, ie. an argument to datatype.OctetString should be passed to network as it is, without further conversion.

    I am using this source as a reference - http://luca.ntop.org/Teaching/Appunti/asn1.html , and from what I see the practical application confirms this.

    opened by jaroszan 14
  •  Rx Interface Support

    Rx Interface Support

    • Support added for Rx Interface.
    • Fix for same hop by hop Id and end to end Id in request and response diameter base messages.
    • Check for non-zero origin state id.
    opened by capgemini-engineering 12
  • CCR - Event-Timestamp

    CCR - Event-Timestamp

    For some reason I am having trouble pulling this value out using the avp struct tags, I can clearly see it in my payload and I can see that it is being correctly decoded in util.go, But I just get an empty time back into my struct.

    However it works if I do a FindAVP(avp.EventTimestamp, 0)

    I am sure I am just missing something..but I am lost as to what I am messing up. any suggestions?

    opened by aaronchar 11
  • support multiple address types

    support multiple address types

    This is the first draft, however I would like to ask for your take on approach taken here before proceeding.

    1. GenericAddress is added without decode function and decode related tests, this domain should probably belong to Address type since diameter has no GenericAddress datatype.
    2. Decode function in address.go is responsible for decoding all datatypes except for reserved ones (0 and 65535)
    3. Currently we are strict in what we receive, but not in what we send. Should Type interface have Serialize function which returns error as well? (for example verifying whether user supplies proper ipv4 and ipv6 address, currently it looks that anything that is not ipv4 is treated as ipv6 in address.go). In generic_address.go I have added print statements to signal errors, but that's definitely not what should be there.

    I have made a basic test to make sure that what is added by GenericAddress is put on the wire in the same way as in the real network traces, but that's all the testing done so far with remote peers.

    opened by jaroszan 11
  • Padding is nonzero

    Padding is nonzero

    When examining pcap files with Wireshark I see that i quite often get a warning saying AVP is malformed because padding is zero. I have noticed this issue only quite recently so could it be that some recent change is responsible for this?

    opened by taseppa 11
  • Missing Origin-State-Id should not make DWR fail since it's optional

    Missing Origin-State-Id should not make DWR fail since it's optional

    Ran into this issue when deploying the sample diameter server: The client I was dealing with was not providing an Origin-State-Id in the DWR commands, which seems to be according to spec.

    Also as per RFC-3588, 5.5.1 + 8.16 (https://tools.ietf.org/html/rfc3588)

    opened by mspronk 10
  • Make certificates optional in ListenAndServeTLS to allow an external callback

    Make certificates optional in ListenAndServeTLS to allow an external callback

    It seems that currently it's not possible to use a callback for fetching TLS certificates on the fly. It's useful for hot replacement of certificates without a need of an application restart. That might be possibly by providing a GetCertificate callback via the tls.Config input of the Server. But the issue is that the ListenAndServeTLS(certFile, keyFile string) unconditionally fills config.Certificates and fails if the certificate files are missing. This can be fixed by means of adding an option into ListenAndServeTLS to skip the lines: https://github.com/fiorix/go-diameter/blob/master/diam/server.go#L697

    config.Certificates = make([]tls.Certificate, 1)
    config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
    

    Or it might check if the config.GetCertificate is nil and load certificates only in that case.

    opened by AlexanderMescheryakov 0
  • diam_sctp_client is crashing on connection

    diam_sctp_client is crashing on connection

    The example SCTP client is crashing with on a type cast when a connection is accepted:

    $ ./main --addr=127.0.0.1:3868
    2022/09/14 10:02:05 Connecting to SCTP server at 127.0.0.1:3868
    panic: interface conversion: net.Conn is *diam.SCTPConn, not *sctp.SCTPConn
    
    goroutine 1 [running]:
    main.main()
            /home/sergii/devel/go-diameter/examples/diam_sctp_client/main.go:58 +0x792
    
    opened by rudchenkos 0
  • unmarshal issue when two avp's with same id but different VendorId used

    unmarshal issue when two avp's with same id but different VendorId used

    It seems the code does not support the case when the same message has two AVPs that have the same avp-id but different VendorIds. I have run into this with the User-Password and 3GPP-Charging-Id used in AAR message - both of these have the avp-id of 2 but the vendorId is different.

    It seems Marshal seems to include the VendorId into the message but unmarshal ignores the VendorId so the data of User-Password gets copied into both the avps.

    I did find a comment like this: // Relies on the fact that in the same app will not be AVPs with same code but different vendorId

    but not sure how it is ok to make such an assumption and why is it necessary. Is it NOT possible to support this case or was it a temporary shortcut? Would it be possible to fix this issue?

    opened by snbuch 0
  • How to parse AVP sub attributes ?

    How to parse AVP sub attributes ?

    I have been struggling with sub attributes of the AVP (3GPP-User-Location-Info), I want to parse the followings attributes under the 3GPP-User-Location-Info

    Tracking Area Identity (TAI) E-UTRAN Cell Global Identifier (ECGI)

    and these 2 attributes also contains some other sub attributes.

    subattr
    opened by nsmosi 0
Owner
Alexandre Fiori
Alexandre Fiori
Package arp implements the ARP protocol, as described in RFC 826. MIT Licensed.

arp Package arp implements the ARP protocol, as described in RFC 826. MIT Licensed. Portions of this code are taken from the Go standard library. The

Matt Layher 305 Dec 20, 2022
A base library defines interfaces and modules of aBFT Lachesis consensus protocol

Lachesis base A base library defines interfaces and modules of aBFT Lachesis consensus protocol. Part of galaxy' s Consensus-as-a-Service for distribu

Galaxy developer Team 10 Oct 25, 2021
Gogrok is a self hosted, easy to use alternative to ngrok. It uses SSH as a base protocol, using channels and existing functionality to tunnel requests to an endpoint.

gogrok A simple, easy to use ngrok alternative (self hosted!) The server and client can also be easily embedded into your applications, see the 'serve

Tyler Stuyfzand 6 Dec 3, 2022
CoAP Client/Server implementing RFC 7252 for the Go Language

Canopus Canopus is a client/server implementation of the Constrained Application Protocol (CoAP) Updates 25.11.2016 I've added basic dTLS Support base

Zubair Hamed 150 Nov 18, 2022
Technical specifications for the IPFS protocol stack

IPFS Specifications This repository contains the specs for the IPFS Protocol and associated subsystems. Understanding the meaning of the spec badges a

IPFS 1k Jan 7, 2023
SMPP 3.4 Protocol for the Go programming language

SMPP 3.4 This is an implementation of SMPP 3.4 for Go, based on the original smpp34 from Kevin Patel. The API has been refactored to idiomatic Go code

Alexandre Fiori 198 Dec 13, 2022
Package dhcp6 implements a DHCPv6 server, as described in RFC 3315. MIT Licensed.

dhcp6 Package dhcp6 implements a DHCPv6 server, as described in IETF RFC 3315. MIT Licensed. At this time, the API is not stable, and may change over

Matt Layher 76 Sep 27, 2022
Fast RFC 5389 STUN implementation in go

STUN Package stun implements Session Traversal Utilities for NAT (STUN) [RFC5389] protocol and client with no external dependencies and zero allocatio

null 487 Nov 28, 2022
URI Templates (RFC 6570) implemented in Go

uritemplates -- import "github.com/jtacoma/uritemplates" Package uritemplates is a level 4 implementation of RFC 6570 (URI Template, http://tools.ietf

Joshua Tacoma 71 Jan 15, 2022
Fast RFC 5389 STUN implementation in go

STUN Package stun implements Session Traversal Utilities for NAT (STUN) [RFC5389] protocol and client with no external dependencies and zero allocatio

null 488 Jan 1, 2023
RFC 1413 compliant fake identd

RFC 1413 compliant fake identd. It is an implementation of the Ident Protocol, but it lies to the clients and always returns fake identities of queried users.

Hyeon Kim (김지현) 3 Oct 29, 2022
Rabbitio - Rabbit stream cipher package RFC 4503 for Go

rabbitio rabbitio is a rabbit stream cipher packge based on RFC 4503 for golang

Sina Ghaderi 8 Dec 14, 2022
wire protocol for multiplexing connections or streams into a single connection, based on a subset of the SSH Connection Protocol

qmux qmux is a wire protocol for multiplexing connections or streams into a single connection. It is based on the SSH Connection Protocol, which is th

Jeff Lindsay 205 Dec 26, 2022
A simple tool to convert socket5 proxy protocol to http proxy protocol

Socket5 to HTTP 这是一个超简单的 Socket5 代理转换成 HTTP 代理的小工具。 如何安装? Golang 用户 # Required Go 1.17+ go install github.com/mritd/s2h@master Docker 用户 docker pull m

mritd 10 Jan 2, 2023
Ebpfmanager - A golang ebpf libary base on cilium/ebpf and datadog/ebpf

介绍 ebpfmanager参照datadog/ebpf/manager包的思想,基于cilium/ebpf实现的ebpf类库封装。 相比cilium/ebpf

null 152 Dec 29, 2022
Open source 5G core network base on 3GPP R15

What is free5GC The free5GC is an open-source project for 5th generation (5G) mobile core networks. The ultimate goal of this project is to implement

free5GC 1.5k Jan 4, 2023
A rule based proxy For Mac base on Clash.

ClashX A rule based proxy For Mac base on Clash. ClashX 旨在提供一个简单轻量化的代理客户端,如果需要更多的定制化,可以考虑使用 CFW Mac 版 Features HTTP/HTTPS and SOCKS protocol Surge lik

Yicheng 21.6k Dec 26, 2022
go stomp server base on net/http

stompserver go stomp server base on "net/http" base on "net/http" and "golang.org/x/net/websocket" so use one port, you can be WebServer or StompServe

0xAAFF 1 Sep 22, 2022