func buildAMQPConfig(rootCACert, dnsResolvers string) (amqp.Config, error) { ret := amqp.Config{Heartbeat: 10 * time.Second} if dnsResolvers != "" { resolvers := dnsdialer.ParseResolvers(dnsResolvers) if len(resolvers) == 0 { return ret, errors.New("No valid DNS resolvers") } ret.Dial = dnsdialer.NewDialer(resolvers).Dial } if rootCACert == "" { return ret, nil } roots := x509.NewCertPool() if !roots.AppendCertsFromPEM([]byte(rootCACert)) { return ret, errors.New("Root certificate not added") } ret.TLSClientConfig = &tls.Config{RootCAs: roots} return ret, nil }
func initMQ(orig_ctx Context, try_proxy bool, proxy string) (ctx Context, err error) { ctx = orig_ctx defer func() { if e := recover(); e != nil { err = fmt.Errorf("initMQ() -> %v", e) } ctx.Channels.Log <- mig.Log{Desc: "leaving initMQ()"}.Debug() }() //Define the AMQP binding ctx.MQ.Bind.Queue = fmt.Sprintf("mig.agt.%s", ctx.Agent.QueueLoc) ctx.MQ.Bind.Key = fmt.Sprintf("mig.agt.%s", ctx.Agent.QueueLoc) // parse the dial string and use TLS if using amqps amqp_uri, err := amqp.ParseURI(AMQPBROKER) if err != nil { panic(err) } ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("AMQP: host=%s, port=%d, vhost=%s", amqp_uri.Host, amqp_uri.Port, amqp_uri.Vhost)}.Debug() if amqp_uri.Scheme == "amqps" { ctx.MQ.UseTLS = true } // create an AMQP configuration with specific timers var dialConfig amqp.Config dialConfig.Heartbeat = 2 * ctx.Sleeper if try_proxy { // if in try_proxy mode, the agent will try to connect to the relay using a CONNECT proxy // but because CONNECT is a HTTP method, not available in AMQP, we need to establish // that connection ourselves, and give it back to the amqp.DialConfig method if proxy == "" { // try to get the proxy from the environemnt (variable HTTP_PROXY) target := "http://" + amqp_uri.Host + ":" + fmt.Sprintf("%d", amqp_uri.Port) req, err := http.NewRequest("GET", target, nil) if err != nil { panic(err) } proxy_url, err := http.ProxyFromEnvironment(req) if err != nil { panic(err) } if proxy_url == nil { panic("Failed to find a suitable proxy in environment") } proxy = proxy_url.Host ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("Found proxy at %s", proxy)}.Debug() } ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("Connecting via proxy %s", proxy)}.Debug() dialConfig.Dial = func(network, addr string) (conn net.Conn, err error) { // connect to the proxy conn, err = net.DialTimeout("tcp", proxy, 5*time.Second) if err != nil { return } // write a CONNECT request in the tcp connection fmt.Fprintf(conn, "CONNECT "+addr+" HTTP/1.1\r\nHost: "+addr+"\r\n\r\n") // verify status is 200, and flush the buffer status, err := bufio.NewReader(conn).ReadString('\n') if err != nil { return } if status == "" || len(status) < 12 { err = fmt.Errorf("Invalid status received from proxy: '%s'", status[0:len(status)-2]) return } // 9th character in response should be "2" // HTTP/1.0 200 Connection established // ^ if status[9] != '2' { err = fmt.Errorf("Invalid status received from proxy: '%s'", status[0:len(status)-2]) return } ctx.Agent.Env.IsProxied = true ctx.Agent.Env.Proxy = proxy return } } else { dialConfig.Dial = func(network, addr string) (net.Conn, error) { return net.DialTimeout(network, addr, 5*time.Second) } } if ctx.MQ.UseTLS { ctx.Channels.Log <- mig.Log{Desc: "Loading AMQPS TLS parameters"}.Debug() // import the client certificates cert, err := tls.X509KeyPair(AGENTCERT, AGENTKEY) if err != nil { panic(err) } // import the ca cert ca := x509.NewCertPool() if ok := ca.AppendCertsFromPEM(CACERT); !ok { panic("failed to import CA Certificate") } TLSconfig := tls.Config{Certificates: []tls.Certificate{cert}, RootCAs: ca, InsecureSkipVerify: false, Rand: rand.Reader} dialConfig.TLSClientConfig = &TLSconfig } // Open AMQP connection ctx.Channels.Log <- mig.Log{Desc: "Establishing connection to relay"}.Debug() ctx.MQ.conn, err = amqp.DialConfig(AMQPBROKER, dialConfig) if err != nil { ctx.Channels.Log <- mig.Log{Desc: "Connection failed"}.Debug() panic(err) } ctx.MQ.Chan, err = ctx.MQ.conn.Channel() if err != nil { panic(err) } // Limit the number of message the channel will receive at once err = ctx.MQ.Chan.Qos(1, // prefetch count (in # of msg) 0, // prefetch size (in bytes) false) // is global _, err = ctx.MQ.Chan.QueueDeclare(ctx.MQ.Bind.Queue, // Queue name true, // is durable false, // is autoDelete false, // is exclusive false, // is noWait nil) // AMQP args if err != nil { panic(err) } err = ctx.MQ.Chan.QueueBind(ctx.MQ.Bind.Queue, // Queue name ctx.MQ.Bind.Key, // Routing key name mig.Mq_Ex_ToAgents, // Exchange name false, // is noWait nil) // AMQP args if err != nil { panic(err) } // Consume AMQP message into channel ctx.MQ.Bind.Chan, err = ctx.MQ.Chan.Consume(ctx.MQ.Bind.Queue, // queue name "", // some tag false, // is autoAck false, // is exclusive false, // is noLocal false, // is noWait nil) // AMQP args if err != nil { panic(err) } return }
func InitMQ(conf MqConf) (amqpChan *amqp.Channel, err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("worker.initMQ() -> %v", e) } }() // create an AMQP configuration with a 10min heartbeat and timeout // dialing address use format "<scheme>://<user>:<pass>@<host>:<port><vhost>" var scheme, user, pass, host, port, vhost string if conf.UseTLS { scheme = "amqps" } else { scheme = "amqp" } if conf.User == "" { panic("MQ User is missing") } user = conf.User if conf.Pass == "" { panic("MQ Pass is missing") } pass = conf.Pass if conf.Host == "" { panic("MQ Host is missing") } host = conf.Host if conf.Port < 1 { panic("MQ Port is missing") } port = fmt.Sprintf("%d", conf.Port) vhost = conf.Vhost dialaddr := scheme + "://" + user + ":" + pass + "@" + host + ":" + port + "/" + vhost timeout, _ := time.ParseDuration(conf.Timeout) var dialConfig amqp.Config dialConfig.Heartbeat = timeout dialConfig.Dial = func(network, addr string) (net.Conn, error) { return net.DialTimeout(network, addr, timeout) } if conf.UseTLS { // import the client certificates cert, err := tls.LoadX509KeyPair(conf.TLScert, conf.TLSkey) if err != nil { panic(err) } // import the ca cert data, err := ioutil.ReadFile(conf.CAcert) ca := x509.NewCertPool() if ok := ca.AppendCertsFromPEM(data); !ok { panic("failed to import CA Certificate") } TLSconfig := tls.Config{Certificates: []tls.Certificate{cert}, RootCAs: ca, InsecureSkipVerify: false, Rand: rand.Reader} dialConfig.TLSClientConfig = &TLSconfig } // Setup the AMQP broker connection amqpConn, err := amqp.DialConfig(dialaddr, dialConfig) if err != nil { panic(err) } amqpChan, err = amqpConn.Channel() if err != nil { panic(err) } return }
// initBroker() sets up the connection to the RabbitMQ broker func initBroker(orig_ctx Context) (ctx Context, err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("initBroker() -> %v", e) } ctx.Channels.Log <- mig.Log{Desc: "leaving initBroker()"}.Debug() }() ctx = orig_ctx // dialing address use format "<scheme>://<user>:<pass>@<host>:<port><vhost>" var scheme, user, pass, host, port, vhost string if ctx.MQ.UseTLS { scheme = "amqps" } else { scheme = "amqp" } if ctx.MQ.User == "" { panic("MQ User is missing") } user = ctx.MQ.User if ctx.MQ.Pass == "" { panic("MQ Pass is missing") } pass = ctx.MQ.Pass if ctx.MQ.Host == "" { panic("MQ Host is missing") } host = ctx.MQ.Host if ctx.MQ.Port < 1 { panic("MQ Port is missing") } port = fmt.Sprintf("%d", ctx.MQ.Port) vhost = ctx.MQ.Vhost dialaddr := scheme + "://" + user + ":" + pass + "@" + host + ":" + port + "/" + vhost if ctx.MQ.Timeout == "" { ctx.MQ.Timeout = "600s" } timeout, err := time.ParseDuration(ctx.MQ.Timeout) if err != nil { panic("Failed to parse timeout duration") } // create an AMQP configuration with specific timers var dialConfig amqp.Config dialConfig.Heartbeat = timeout dialConfig.Dial = func(network, addr string) (net.Conn, error) { return net.DialTimeout(network, addr, timeout) } // create the TLS configuration if ctx.MQ.UseTLS { // import the client certificates cert, err := tls.LoadX509KeyPair(ctx.MQ.TLScert, ctx.MQ.TLSkey) if err != nil { panic(err) } // import the ca cert data, err := ioutil.ReadFile(ctx.MQ.CAcert) ca := x509.NewCertPool() if ok := ca.AppendCertsFromPEM(data); !ok { panic("failed to import CA Certificate") } TLSconfig := tls.Config{Certificates: []tls.Certificate{cert}, RootCAs: ca, InsecureSkipVerify: false, Rand: rand.Reader} dialConfig.TLSClientConfig = &TLSconfig } // Setup the AMQP broker connection ctx.MQ.conn, err = amqp.DialConfig(dialaddr, dialConfig) if err != nil { panic(err) } ctx.MQ.Chan, err = ctx.MQ.conn.Channel() if err != nil { panic(err) } // declare the "mig" exchange used for all publications err = ctx.MQ.Chan.ExchangeDeclare("mig", "topic", true, false, false, false, nil) if err != nil { panic(err) } ctx.Channels.Log <- mig.Log{Sev: "info", Desc: "AMQP connection opened"} return }
// InitAmqp establishes a connection to the rabbitmq endpoint defined in the configuration func InitAmqp(conf MqConf) (p Publisher, err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("InitAmqp failed with error: %v", e) } }() var scheme, user, pass, host, port, vhost string if conf.UseTLS { scheme = "amqps" } else { scheme = "amqp" } if conf.User == "" { panic("MQ User is missing") } user = conf.User if conf.Pass == "" { panic("MQ Pass is missing") } pass = conf.Pass if conf.Host == "" { panic("MQ Host is missing") } host = conf.Host if conf.Port < 1 { panic("MQ Port is missing") } port = fmt.Sprintf("%d", conf.Port) vhost = conf.Vhost dialaddr := scheme + "://" + user + ":" + pass + "@" + host + ":" + port + "/" + vhost timeout, _ := time.ParseDuration(conf.Timeout) var dialConfig amqp.Config dialConfig.Heartbeat = timeout dialConfig.Dial = func(network, addr string) (net.Conn, error) { return net.DialTimeout(network, addr, timeout) } if conf.UseTLS { // import the ca cert data, err := ioutil.ReadFile(conf.CACertPath) if err != nil { panic(err) } ca := x509.NewCertPool() if ok := ca.AppendCertsFromPEM(data); !ok { panic("failed to import CA Certificate") } TLSconfig := tls.Config{ RootCAs: ca, InsecureSkipVerify: false, Rand: rand.Reader, } dialConfig.TLSClientConfig = &TLSconfig if conf.ClientCertPath != "" && conf.ClientKeyPath != "" { // import the client certificates cert, err := tls.LoadX509KeyPair(conf.ClientCertPath, conf.ClientKeyPath) if err != nil { panic(err) } TLSconfig.Certificates = []tls.Certificate{cert} } } // Setup the AMQP broker connection amqpConn, err := amqp.DialConfig(dialaddr, dialConfig) if err != nil { panic(err) } p.amqpChan, err = amqpConn.Channel() if err != nil { panic(err) } p.use_amqp = true p.mqconf = conf return }
func initMQ(orig_ctx Context) (ctx Context, err error) { ctx = orig_ctx defer func() { if e := recover(); e != nil { err = fmt.Errorf("initMQ() -> %v", e) } ctx.Channels.Log <- mig.Log{Desc: "leaving initMQ()"}.Debug() }() //Define the AMQP binding ctx.MQ.Bind.Queue = fmt.Sprintf("mig.agt.%s", ctx.Agent.QueueLoc) ctx.MQ.Bind.Key = fmt.Sprintf("mig.agt.%s", ctx.Agent.QueueLoc) // parse the dial string and use TLS if using amqps if strings.Contains(AMQPBROKER, "amqps://") { ctx.MQ.UseTLS = true } // create an AMQP configuration with specific timers var dialConfig amqp.Config dialConfig.ConnectionTimeout = 10 * ctx.Sleeper dialConfig.Heartbeat = 2 * ctx.Sleeper if ctx.MQ.UseTLS { // import the client certificates cert, err := tls.X509KeyPair([]byte(AGENTCERT), []byte(AGENTKEY)) if err != nil { panic(err) } // import the ca cert ca := x509.NewCertPool() if ok := ca.AppendCertsFromPEM([]byte(CACERT)); !ok { panic("failed to import CA Certificate") } TLSconfig := tls.Config{Certificates: []tls.Certificate{cert}, RootCAs: ca, InsecureSkipVerify: false, Rand: rand.Reader} dialConfig.TLSClientConfig = &TLSconfig } // Open a non-encrypted AMQP connection ctx.MQ.conn, err = amqp.DialConfig(AMQPBROKER, dialConfig) if err != nil { panic(err) } ctx.MQ.Chan, err = ctx.MQ.conn.Channel() if err != nil { panic(err) } // Limit the number of message the channel will receive at once err = ctx.MQ.Chan.Qos(7, // prefetch count (in # of msg) 0, // prefetch size (in bytes) false) // is global _, err = ctx.MQ.Chan.QueueDeclare(ctx.MQ.Bind.Queue, // Queue name true, // is durable false, // is autoDelete false, // is exclusive false, // is noWait nil) // AMQP args if err != nil { panic(err) } err = ctx.MQ.Chan.QueueBind(ctx.MQ.Bind.Queue, // Queue name ctx.MQ.Bind.Key, // Routing key name "mig", // Exchange name false, // is noWait nil) // AMQP args if err != nil { panic(err) } // Consume AMQP message into channel ctx.MQ.Bind.Chan, err = ctx.MQ.Chan.Consume(ctx.MQ.Bind.Queue, // queue name "", // some tag false, // is autoAck false, // is exclusive false, // is noLocal false, // is noWait nil) // AMQP args if err != nil { panic(err) } return }