How to pass port to ziticontext in golang

I am using a custom dialer to call a ziti service:

func (cd *CustomDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
	add := strings.Split(address, ":")
	return cd.zitiContext.Dial(add[0])
}

func (cd *CustomDialer) Dial(network, address string) (net.Conn, error) {
	add := strings.Split(address, ":")
	return cd.zitiContext.Dial(add[0])
}

If i try to Dial with port included, it can't find the service. But my service uses multiple ports and does different things when called on a different port. How do i call a service with a specific port?

Thanks!

Hi @CarlosHleb,

What's on the far side from that golang dialer? Is it a tunneler or is it a service you're writing? I am assuming that it's a tunneler? It will matter as to what kind of answer you get. :slight_smile:

It loads a zitiContext from identity json. It's not a service.

Sorry, it seems I wasn't clear. On the near side you have a golang project that loads an identity from a json file. That golang program dials a service on the far side of the OpenZiti overlay -- the remote machine.

Is the target identity, the remote identity, a tunneler (ziti-edge-tunnel, ziti desktop edge for windows, , a router in tunneling mode, etc), or is it an SDK-based application?

I assume it's a tunneler since you're talking about ports on the remote side. It makes me think you're offloading from the overlay onto the IP-based underlay network towards some port using a tunneler, is that correct?

If that's the case, then I need to know how your service is declared. Again, I have to guess but my guess is that you've configured multiple intercepts on your service and you've configured the far side of the connection (the terminating side) to forward ports?

That's why I was asking, I need to make some assumptions... Can you confirm what the service looks like too? Is it forwarding ports?

With a service configured to forward ports at the host side, and with those ports on the intercept side, here's an example function that will allow you to dial that function by url:


type ZitiDialer struct {
	underlayDialer *net.Dialer
}

func (z ZitiDialer) Dial(network, address string) (net.Conn, error) {
	return z.underlayDialer.Dial(network, address)
}

func createZitifiedHttpClient(idFile string) http.Client {
	cfg, err := ziti.NewConfigFromFile(idFile)
	if err != nil {
		panic(err)
	}

	ctx, err := ziti.NewContext(cfg)
	if err != nil {
		panic(err)
	}

	zitiContexts := ziti.NewSdkCollection()
	zitiContexts.Add(ctx)
	zitiTransport := http.DefaultTransport.(*http.Transport).Clone() // copy default transport
	zitiTransport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
		fallback := &ZitiDialer{
			underlayDialer: &net.Dialer{},
		}
		dialer := zitiContexts.NewDialerWithFallback(ctx, fallback)
		return dialer.Dial(network, addr)
	}
	return http.Client{Transport: zitiTransport}
}

you'd then use that function with something like:

	id := `/tmp/identity.json`
	httpClient := createZitifiedHttpClient(id)
	resp, _ := httpClient.Get("http://docker.whale.ziti:2000")
	body, _ := io.ReadAll(resp.Body)
	fmt.Println("Hello response:", string(body))
1 Like

This is what i was looking for, Thanks!

Hello, i don't know what happened, but it stopped working.
This is how i create my service:

#!/bin/bash

source .env

function zitiEx {
  docker compose \
    exec -it ziti-edge-router \
    /var/openziti/ziti-bin/ziti "$@";
}

zitiEx edge login ${ZITI_CTRL_EDGE_ADVERTISED_ADDRESS}:$ZITI_CTRL_EDGE_ADVERTISED_PORT -u $ZITI_USER -p $ZITI_PWD --yes

ZITI_SERVICE_LIVEKIT="someservicename"
DMZ_PORT=443

zitiEx edge create config ${ZITI_SERVICE_LIVEKIT}.host.config host.v1 '{
    "address": "dmz-server",
    "port": 443,
    "protocol": "tcp"
}'
zitiEx edge create config ${ZITI_SERVICE_LIVEKIT}.int.config intercept.v1 '{
  "protocols":["tcp"],
  "addresses":["11.11.11.11"],
  "portRanges":[{"low":443, "high":443}]
}'
zitiEx edge create service ${ZITI_SERVICE_LIVEKIT} --configs ${ZITI_SERVICE_LIVEKIT}".host.config",${ZITI_SERVICE_LIVEKIT}".int.config"
zitiEx edge create service-policy ${ZITI_SERVICE_LIVEKIT}".bind" Bind --service-roles "@"${ZITI_SERVICE_LIVEKIT} --identity-roles "#"${ZITI_SERVICE_LIVEKIT}".bind"
zitiEx edge create service-policy ${ZITI_SERVICE_LIVEKIT}".dial" Dial --service-roles "@"${ZITI_SERVICE_LIVEKIT} --identity-roles "#"${ZITI_SERVICE_LIVEKIT}".dial"


zitiEx edge update identity ${ZITI_ROUTER_NAME} -a ${ZITI_SERVICE_API}.bind \
  -a ${ZITI_SERVICE_LIVEKIT}.bind

and then i call the service with:

func CreateZitifiedHttpClient(idFile string) http.Client {
	cfg, err := ziti.NewConfigFromFile(idFile)
	if err != nil {
		panic(err)
	}

	ctx, err := ziti.NewContext(cfg)
	if err != nil {
		panic(err)
	}

	zitiContexts := ziti.NewSdkCollection()
	zitiContexts.Add(ctx)
	zitiTransport := http.DefaultTransport.(*http.Transport).Clone() // copy default transport
	zitiTransport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {

		// host := strings.Split(addr, ":")[0]
		// zitiConn, err := ZitiContext.Dial(host)
		// if err == nil {
		// 	// If Ziti connection is successful, return it
		// 	return zitiConn, nil
		// }

		fallback := &fallbackDialer{
			underlayDialer: &net.Dialer{},
		}
		dialer := zitiContexts.NewDialerWithFallback(ctx, fallback)
		return dialer.Dial(network, addr)
	}
	return http.Client{Transport: zitiTransport}
}

	transport := openziti.CreateZitifiedHttpClient("./enroller.json")
	resp, err := transport.Get("https://11.11.11.11:443/")
	fmt.Print(err)
	body, _ := io.ReadAll(resp.Body)
	fmt.Println("Hello response:", string(body))

It gives me connection timeout error. The identity can access that service(if i load it in my local machines tuneler and then try to open https://11.11.11.11 in my browser, it opens. But not from my script.

I did a quick review and it seems ok from first inspection. Can you grab the logs from the golang process? My guess is that the identity is somehow not authorized and the underlay dialer is being used but the logs from the go process should clarify that.

I know you stated that the identity can indeed access the service, but in my experience it's easy to get something stale in docker that I was certain I had correct.

Get "https://11.11.11.11:443/": dial tcp 11.11.11.11:443: connect: connection timed out

All the logs, not just the timeout. Are there no other logs output?

If i try to use a hostname:

Get "https://dmz.r1.bct.tech:443/": dial tcp: lookup dmz.r1.bct.tech on 127.0.0.53:53: server misbehaving

heres logs from ziti controller/router:

ziti-edge-router-1                | [ 240.004] WARNING ziti/router/forwarder.(*Scanner).scan: {ctrlId=[ziti-controller] idleTime=[2m12.491s] idleThreshold=[1m0s] circuitId=[U-7Yt-gxl]} circuit exceeds idle threshold
ziti-edge-router-1                | [ 240.004] WARNING ziti/router/forwarder.(*Scanner).scan: {ctrlId=[ziti-controller] circuitCount=[1]} sent confirmation for circuits
ziti-controller-1                 | [ 246.764]    INFO ziti/controller/handler_ctrl.(*circuitConfirmationHandler).HandleReceive: {routerId=[BKWZsCfv9] circuitCount=[1]} received circuit confirmation request

Any ideas? I have tried everything i can think of :confused:

Can you share the logs from the golang process? By default you should be seeing at least the ziti session get created. I would increase the log level with the golang process and post the logs back here pls.

If your code is somewhere in the open and I can look at it, send that link and I'll check it out.

If you'd like a simple example demonstrating how to "do" what you're trying to do, I could do that too but I'd need a bit of help to understand what it is you're trying to do and in what environment.

The fact that you stated: "i don't know what happened, but it stopped working." makes me think this is just policy-related...

You could also run ziti edge policy-advisor identities -q and make sure the identities trying to dial have the dial permissoin and the identities trying to bind have the bind permission...

How do you increase the log level for go process?

By go process you mean my app that uses the openzitis golangs sdk, right?

yes, the output from the go process that's not intercepting correctly. Currently the ziti golang sdk uses the logrus standard logger so you could do:

		logrus.StandardLogger().Level = logrus.DebugLevel

If you could set the environment variable too: PFXLOG_NO_JSON=true the output won't be in json... Share the outptut, it'll look something like this


time="2024-09-10T14:54:28-04:00" level=debug msg="attempting to authenticate"
time="2024-09-10T14:54:28-04:00" level=debug msg="setting active controller" key="https://ec2-3-18-113-162.us-east-2.compute.amazonaws.com:8441/edge/client/v1"
time="2024-09-10T14:54:28-04:00" level=debug msg="no additional controllers reported, continuing with 1 default configured controller"
time="2024-09-10T14:54:28-04:00" level=debug msg="checking if service updates available"
time="2024-09-10T14:54:28-04:00" level=debug msg="refreshing services"
time="2024-09-10T14:54:28-04:00" level=debug msg="processing service updates with 1 services"
time="2024-09-10T14:54:28-04:00" level=debug msg="no service config of type intercept.v1 defined for service" serviceId=7TVsiEfcrjaTnOCHlEfjbU serviceName=zsshSvc
...
...
...

I did this

	logrus.StandardLogger().Level = logrus.DebugLevel
	transport := openziti.CreateZitifiedHttpClient("./enroller.json")
	// 188.64.207.188
	resp, err := transport.Get("https://dmz.r1.bct.tech:443/")
	fmt.Print(err)
	body, _ := io.ReadAll(resp.Body)
	fmt.Println("Hello response:", string(body))
	panic("dsdss")

The logs didnt change.

can you share "the logs" with me so i can see them? I still want to see all the output of running your golang process. If you want to DM them to me and not post them in public that works for me.

I'll offer again - would you like me to make you a step-by-step guide? Would that be easier? If so - i can do that...

This is the full output if the code i provided before:

carlos@carlos:~/Projects/screen-control/screen-control-agent/agent$ ./agent 
2024/09/10 22:33:35 setup.go:92: /home/carlos/Projects/screen-control/screen-control-agent/agent/enroller.json
Get "https://dmz.r1.bct.tech:443/": dial tcp: lookup dmz.r1.bct.tech on 127.0.0.53:53: server misbehavingpanic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x40 pc=0x9ccd35]

goroutine 1 [running]:
agent/agent/enroller.CreateDevice()
        /home/carlos/Projects/screen-control/screen-control-agent/agent/enroller/enroller.go:65 +0x515
agent/agent/app.Run()
        /home/carlos/Projects/screen-control/screen-control-agent/agent/app/app.go:54 +0x2d4
main.main()
        /home/carlos/Projects/screen-control/screen-control-agent/agent/main.go:18 +0x59

Cool thanks for that. I have a better idea now of what you are doing and what you've been trying to tell/show me... I assume enroller.go is trying to make that http request, returning nil and causing the nil pointer issue using that code you showed, right? Assuming so, I assume it's the io.ReadAll(resp.Body) causing the panic?

can you run the ziti CLI and show the output of policy-advisor? (replace $nameOfTheIdentityhere with the actual identity name)

ziti edge policy-advisor identities $nameOfTheIdentityhere -q 

let's make sure the identity represented by enroller.json has access to the service

Yes the resp.Body causes the panic.

Heres the output:

ziti@d69c91070d58:/persistent$ ziti edge policy-advisor identities enroller-for-cusid-1  -q
OKAY : enroller-for-cusid-1 (1) -> dmz.r1.bct.tech (1) Common Routers: (1/1) Dial: Y Bind: N