Esempio n. 1
0
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
}
Esempio n. 2
0
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
}
Esempio n. 3
0
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
}
Esempio n. 4
0
// 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
}
Esempio n. 5
0
// 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
}
Esempio n. 6
0
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
}